AgentStack
SKILL verified MIT Self-run

Qgis Impl Network Analysis

skill-impertio-studio-qgis-claude-skill-package-qgis-impl-network-analysis · by Impertio-Studio

>

No reviews yet
0 installs
13 views
0.0% view→install

Install

$ agentstack add skill-impertio-studio-qgis-claude-skill-package-qgis-impl-network-analysis

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Qgis Impl Network Analysis? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

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

# 1. Load road network layer
roads = QgsProject.instance().mapLayersByName("roads")[0]

# 2. Configure director (bidirectional, no direction field)
director = QgsVectorLayerDirector(
    roads,
    -1,                                    # No direction field
    '', '', '',                            # Direction values (unused)
    QgsVectorLayerDirector.DirectionBoth   # Default direction
)

# 3. Add distance-based cost strategy
director.addStrategy(QgsNetworkDistanceStrategy())

# 4. Define origin and destination
start_point = QgsPointXY(5.1214, 52.0907)   # Utrecht
end_point = QgsPointXY(4.8952, 52.3702)     # Amsterdam

# 5. Build graph (points get snapped to nearest network edge)
builder = QgsGraphBuilder(roads.crs())
tied_points = director.makeGraph(builder, [start_point, end_point])
graph = builder.graph()

# 6. Get vertex IDs from tied (snapped) points
start_id = graph.findVertex(tied_points[0])
end_id = graph.findVertex(tied_points[1])

# 7. Run Dijkstra from start vertex (criterion 0 = distance)
(tree, cost) = QgsGraphAnalyzer.dijkstra(graph, start_id, 0)

# 8. Check reachability
if tree[end_id] == -1:
    raise ValueError("Destination is unreachable from origin")

# 9. Reconstruct path (walk backwards from destination)
route_points = [graph.vertex(end_id).point()]
current = end_id
while current != start_id:
    edge = graph.edge(tree[current])
    current = edge.fromVertex()
    route_points.insert(0, graph.vertex(current).point())

# 10. Build route geometry
route_geom = QgsGeometry.fromPolyline(
    [QgsPoint(p.x(), p.y()) for p in route_points]
)
print(f"Route distance: {cost[end_id]:.1f} map units")

Pattern 2: One-Way Street Handling

# Find the direction field index
oneway_idx = roads.fields().indexOf('oneway')

director = QgsVectorLayerDirector(
    roads,
    oneway_idx,                            # Field containing direction info
    'F',                                   # Value meaning "forward only"
    'T',                                   # Value meaning "reverse only"
    'B',                                   # Value meaning "both directions"
    QgsVectorLayerDirector.DirectionBoth   # Default for unmatched values
)

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,              # Default speed when field value is NULL
    1000.0 / 3600.0    # Conversion factor: km/h to m/s
)
director.addStrategy(strategy)

Pattern 4: Multiple Cost Criteria

# Criterion 0: distance
director.addStrategy(QgsNetworkDistanceStrategy())

# Criterion 1: travel time
speed_idx = roads.fields().indexOf('speed_kmh')
director.addStrategy(QgsNetworkSpeedStrategy(speed_idx, 50.0, 1000.0 / 3600.0))

# Build graph once
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])

# Shortest by distance (criterion 0)
(tree_dist, cost_dist) = QgsGraphAnalyzer.dijkstra(graph, sid, 0)

# Fastest by travel time (criterion 1)
(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  # 5000 meters (or seconds, depending on strategy)

# Collect fully reachable vertices (interior)
reachable = []
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)

# Combine all reachable points for convex hull / polygon
all_points = reachable + boundary

Pattern 6: Shortest Path Tree

# Get the full shortest path tree from a single origin
tree_graph = QgsGraphAnalyzer.shortestTree(graph, start_id, 0)

# tree_graph is a new QgsGraph containing only edges in the shortest path tree
# Extract all edges for visualization
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()
    # Create line geometry for each edge
    line = QgsGeometry.fromPolylineXY([from_pt, to_pt])

Common Operations

Using Processing Algorithms for Routing

import processing

# Shortest path: point to point
result = processing.run("native:shortestpathpointtopoint", {
    'INPUT': roads,
    'STRATEGY': 0,              # 0=Shortest, 1=Fastest
    'DIRECTION_FIELD': 'oneway',
    'VALUE_FORWARD': 'F',
    'VALUE_BACKWARD': 'T',
    'VALUE_BOTH': 'B',
    'DEFAULT_DIRECTION': 2,     # 0=Forward, 1=Backward, 2=Both
    '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,              # 0=Shortest, 1=Fastest
    '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,      # Distance or time threshold
    'OUTPUT': 'TEMPORARY_OUTPUT'
})

Creating a Route Layer from Graph Results

from qgis.core import QgsVectorLayer, QgsFeature, QgsField
from qgis.PyQt.QtCore import QVariant

# Create memory layer for the route
route_layer = QgsVectorLayer(
    f"LineString?crs={roads.crs().authid()}",
    "Route",
    "memory"
)
provider = route_layer.dataProvider()
provider.addAttributes([
    QgsField("distance", QVariant.Double),
])
route_layer.updateFields()

# Add route feature
feat = QgsFeature()
feat.setGeometry(route_geom)
feat.setAttributes([cost[end_id]])
provider.addFeature(feat)
route_layer.updateExtents()

QgsProject.instance().addMapLayer(route_layer)

Reference Links

  • [references/methods.md](references/methods.md) -- API signatures for QgsGraphBuilder, QgsGraphAnalyzer, QgsVectorLayerDirector, strategy classes
  • [references/examples.md](references/examples.md) -- Complete working examples for routing and service area workflows
  • [references/anti-patterns.md](references/anti-patterns.md) -- Common mistakes in network analysis with corrections

Official Sources

  • https://docs.qgis.org/3.34/en/docs/pyqgisdevelopercookbook/network_analysis.html
  • https://qgis.org/pyqgis/3.34/analysis/QgsGraphAnalyzer.html
  • https://qgis.org/pyqgis/3.34/analysis/QgsGraphBuilder.html
  • https://qgis.org/pyqgis/3.34/analysis/QgsVectorLayerDirector.html

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.