AgentStack
SKILL verified MIT Self-run

Qgis Syntax Pyqgis Api

skill-impertio-studio-qgis-claude-skill-package-qgis-syntax-pyqgis-api · by Impertio-Studio

>

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

Install

$ agentstack add skill-impertio-studio-qgis-claude-skill-package-qgis-syntax-pyqgis-api

✓ 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 Syntax Pyqgis Api? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

qgis-syntax-pyqgis-api

Quick Reference

Scripting Contexts

| Context | iface Available | Initialization Required | Use Case | |---------|-------------------|------------------------|----------| | Python Console | Yes | None | Interactive exploration, quick tests | | Standalone Script | No | QgsApplication([], False) + initQgis() | CLI tools, CI pipelines, batch processing | | Processing Script | No (feedback instead) | None (framework handles it) | Geoprocessing algorithms | | Plugin | Yes (via classFactory) | None | GUI extensions, toolbar tools |

Core Classes

| Class | Purpose | Key Methods | |-------|---------|-------------| | QgsFeature | Single feature (geometry + attributes) | id(), geometry(), attributes(), __getitem__() | | QgsFeatureRequest | Filter/optimize feature queries | setFilterExpression(), setFilterRect(), setLimit(), setFlags() | | QgsGeometry | Geometry wrapper with GEOS operations | fromPointXY(), buffer(), intersection(), contains() | | QgsSpatialIndex | R-tree spatial index | addFeature(), nearestNeighbor(), intersects() | | QgsTask | Background processing | run(), finished(), setProgress(), isCanceled() | | QgsMessageLog | Log panel messages | logMessage(msg, tag, level) | | QgsMessageBar | Map canvas notifications | pushMessage(title, text, level, duration) |

QgsPoint vs QgsPointXY

| Class | Dimensions | Use With | |-------|-----------|----------| | QgsPointXY | 2D (X, Y) only | fromPointXY(), fromPolylineXY(), fromPolygonXY() | | QgsPoint | 2D + Z + M | fromPolyline(), 3D operations |

ALWAYS use QgsPointXY for 2D operations. Use QgsPoint ONLY when Z or M values are required.


Critical Warnings

NEVER modify features outside an edit session. Changes are silently lost or corrupt the data source. ALWAYS use with edit(layer): or manually call startEditing() / commitChanges().

NEVER access iface, QgsProject.instance(), or any Qt widget from QgsTask.run(). These are main-thread objects. Accessing them from a background thread crashes QGIS.

NEVER raise exceptions in QgsTask.run(). ALWAYS catch exceptions internally and return False on failure.

NEVER use layer.featureCount() to check if features exist. Some providers return -1. ALWAYS use getFeatures() with setLimit(1) instead.

NEVER use print() in multithreaded code (expression functions, renderers, processing algorithms). ALWAYS use QgsMessageLog instead.

ALWAYS check for NULL geometries before operations: if not geom.isNull():.

ALWAYS use QgsDistanceArea for measurements on geographic (lat/lon) CRS. The simple area() and length() methods return values in layer units without CRS correction.

ALWAYS call layer.updateFields() after adding or removing fields via the data provider.

ALWAYS keep QgsProcessingContext and QgsProcessingFeedback alive for the duration of QgsProcessingAlgRunnerTask. Garbage collection crashes QGIS.


Decision Tree: Scripting Context

Need to write PyQGIS code?
|
+-- Running inside QGIS GUI?
|   |
|   +-- Quick test or exploration? --> Python Console (iface available)
|   +-- Reusable geoprocessing? --> Processing Script (QgsProcessingAlgorithm)
|   +-- GUI extension with toolbar? --> Plugin (classFactory + initGui/unload)
|
+-- Running outside QGIS?
    --> Standalone Script (QgsApplication init required)

Decision Tree: Feature Editing

Need to modify layer data?
|
+-- Bulk import / batch processing, no undo needed?
|   --> Data Provider direct: layer.dataProvider().addFeatures([...])
|
+-- Interactive editing, undo/redo needed?
|   --> Edit Buffer: with edit(layer): layer.addFeature(feat)
|
+-- Multiple edits as single undo operation?
    --> Edit Commands: layer.beginEditCommand("description")

Decision Tree: Spatial Queries

Need to find features by location?
|
+-- Single query against a layer?
|   --> QgsFeatureRequest().setFilterRect(extent)
|
+-- Repeated queries against same dataset?
|   |
|   +-- Point data only?
|   |   --> QgsSpatialIndexKDBush (fastest, static)
|   |
|   +-- Mixed geometry types?
|       --> QgsSpatialIndex (R-tree, dynamic)

Essential Patterns

Standalone Script Initialization

from qgis.core import QgsApplication, QgsVectorLayer

qgs = QgsApplication([], False)
qgs.initQgis()

# ... PyQGIS work here ...

qgs.exitQgis()  # ALWAYS clean up

Dual-Context Script (Console + Standalone)

try:
    from qgis.utils import iface
    layer = iface.activeLayer()
except ImportError:
    from qgis.core import QgsApplication
    qgs = QgsApplication([], False)
    qgs.initQgis()

Feature Iteration with Optimization

from qgis.core import QgsFeatureRequest

# Attributes only (skip geometry loading)
request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry)
request.setSubsetOfAttributes(['name', 'population'], layer.fields())

for feature in layer.getFeatures(request):
    print(feature['name'], feature['population'])

Feature Editing with Context Manager

from qgis.core import QgsFeature, QgsGeometry, QgsPointXY, edit

with edit(layer):
    feat = QgsFeature(layer.fields())
    feat.setAttributes([1, 'New Point'])
    feat.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(10.0, 52.0)))
    layer.addFeature(feat)
# commitChanges() called automatically; rollBack() on exception

Geometry Construction and Operations

from qgis.core import QgsGeometry, QgsPointXY

# Create geometries
point = QgsGeometry.fromPointXY(QgsPointXY(1.0, 2.0))
polygon = QgsGeometry.fromPolygonXY([[
    QgsPointXY(0, 0), QgsPointXY(2, 0),
    QgsPointXY(2, 2), QgsPointXY(0, 2), QgsPointXY(0, 0)
]])

# Predicates
if polygon.contains(point):
    print("Point is inside polygon")

# Operations
buffered = point.buffer(10.0, 5)
intersection = polygon.intersection(buffered)

Spatial Index Usage

from qgis.core import QgsSpatialIndex, QgsPointXY, QgsFeatureRequest

# Build index (bulk load is fastest)
index = QgsSpatialIndex(layer.getFeatures())

# Query nearest 5 features
nearest_ids = index.nearestNeighbor(QgsPointXY(25.4, 12.7), 5)

# Fetch actual features by ID
for fid in nearest_ids:
    feature = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(fid)))

Background Task (QgsTask Subclass)

from qgis.core import QgsTask, QgsApplication, QgsMessageLog, Qgis

class ProcessingTask(QgsTask):
    def __init__(self, description, data):
        super().__init__(description, QgsTask.CanCancel)
        self.data = data  # Copy data BEFORE task starts
        self.result = None
        self.exception = None

    def run(self):
        """Background thread. NEVER access iface or QgsProject here."""
        try:
            for i, item in enumerate(self.data):
                if self.isCanceled():
                    return False
                self.result = process(item)
                self.setProgress((i + 1) / len(self.data) * 100)
            return True
        except Exception as e:
            self.exception = e
            return False

    def finished(self, result):
        """Main thread. Safe for GUI updates."""
        if result:
            QgsMessageLog.logMessage("Done", 'MyPlugin', Qgis.Success)
        elif self.exception:
            QgsMessageLog.logMessage(str(self.exception), 'MyPlugin', Qgis.Critical)

task = ProcessingTask("Heavy work", data_copy)
QgsApplication.taskManager().addTask(task)

User Communication

from qgis.core import QgsMessageLog, Qgis

# Log panel (always available, including background threads)
QgsMessageLog.logMessage("Info message", 'MyPlugin', Qgis.Info)
QgsMessageLog.logMessage("Warning", 'MyPlugin', Qgis.Warning)
QgsMessageLog.logMessage("Error", 'MyPlugin', Qgis.Critical)

# Message bar (main thread + iface only)
iface.messageBar().pushMessage("Title", "Text", level=Qgis.Success, duration=3)

Common Operations

Check If Layer Has Features

request = QgsFeatureRequest().setLimit(1)
has_features = bool(list(layer.getFeatures(request)))

Get Single Feature by ID

feature = next(layer.getFeatures(QgsFeatureRequest().setFilterFid(42)))

Add Fields to Layer

from qgis.PyQt.QtCore import QMetaType
from qgis.core import QgsField

layer.dataProvider().addAttributes([
    QgsField("name", QMetaType.Type.QString),
    QgsField("value", QMetaType.Type.Double),
])
layer.updateFields()  # ALWAYS call after field changes

Ellipsoid-Accurate Measurements

from qgis.core import QgsDistanceArea, QgsUnitTypes

d = QgsDistanceArea()
d.setEllipsoid('WGS84')

area_m2 = d.measureArea(geom)
area_km2 = d.convertAreaMeasurement(area_m2, QgsUnitTypes.AreaSquareKilometers)

Coordinate Transformation

from qgis.core import QgsCoordinateTransform, QgsCoordinateReferenceSystem, QgsProject

transform = QgsCoordinateTransform(
    QgsCoordinateReferenceSystem("EPSG:4326"),
    QgsCoordinateReferenceSystem("EPSG:3857"),
    QgsProject.instance()
)
geom.transform(transform)  # In-place transformation

Basic Symbology

from qgis.core import QgsMarkerSymbol

symbol = QgsMarkerSymbol.createSimple({'name': 'circle', 'color': 'red', 'size': '3'})
layer.renderer().setSymbol(symbol)
layer.triggerRepaint()

Renderer Types Overview

| Renderer | Class | Use Case | |----------|-------|----------| | Single Symbol | QgsSingleSymbolRenderer | All features same style | | Categorized | QgsCategorizedSymbolRenderer | Discrete attribute values | | Graduated | QgsGraduatedSymbolRenderer | Numeric ranges | | Rule-Based | QgsRuleBasedRenderer | Expression-driven rules |


Data Provider vs Edit Buffer

| Aspect | Data Provider | Edit Buffer | |--------|--------------|-------------| | Method | layer.dataProvider().addFeatures() | layer.addFeature() | | Undo support | No | Yes | | Edit session required | No | Yes | | Performance | Faster for bulk operations | Slower, safer | | Use case | Batch processing, scripts | Interactive editing |


Reference Links

  • [references/methods.md](references/methods.md) -- API signatures for QgsFeature, QgsFeatureRequest, QgsGeometry, QgsSpatialIndex, QgsTask
  • [references/examples.md](references/examples.md) -- Working code examples for all major patterns
  • [references/anti-patterns.md](references/anti-patterns.md) -- Editing, threading, and iteration anti-patterns

Official Sources

  • https://docs.qgis.org/latest/en/docs/pyqgisdevelopercookbook/vector.html
  • https://docs.qgis.org/latest/en/docs/pyqgisdevelopercookbook/geometry.html
  • https://docs.qgis.org/latest/en/docs/pyqgisdevelopercookbook/tasks.html
  • https://docs.qgis.org/latest/en/docs/pyqgisdevelopercookbook/communicating.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.