2

I have a script that creates a multi-distance buffer rings and have managed to migrate it successfully to QGIS 3.4.5. This script requires me to select a layer, and a feature in the layer before I run it, as such:

from math import *
from qgis.core import *
from qgis.utils import iface
from PyQt5.QtCore import *

geom = iface.activeLayer().selectedFeatures()[0].geometry()

start_x = geom.asPoint().x()
start_y = geom.asPoint().y()
sides = 64
radius = 6378137.0  # meters

# create layer
vl = QgsVectorLayer("Polygon", "Distance Buffers", "memory")
pr = vl.dataProvider()

# changes are only possible when editing the layer
vl.startEditing()

# add fields
pr.addAttributes([QgsField("Distance", QVariant.Int), QgsField("Label", QVariant.String)])

distance = [250, 500, 1000, 2000, 3000, 4000, 5000, 10000, 15000, 20000, 25000, 30000, 40000, 50000]
for i in range(len(distance)):
    points = []
    dist = distance[i]
    degrees = 0
    while degrees <= 360:
        degrees = degrees + 360 / sides

        start_lon = start_x * pi / 180
        start_lat = start_y * pi / 180
        bearing = degrees * pi / 180

        end_lat = asin((sin(start_lat) * cos(dist / radius)) + (cos(start_lat) * sin(dist / radius) * cos(bearing)))
        end_lon = start_lon + atan2(sin(bearing) * sin(dist / radius) * cos(start_lat),
                                    cos(dist / radius) - (sin(start_lat) * sin(end_lat)))

        points.append(QgsPointXY(end_lon * 180 / pi, end_lat * 180 / pi))

        fet_name = str(distance[i])
        if distance[i] < 1000:
            label = str(distance[i]) + "m"
        else:
            label = str(distance[i]/1000) + "km"

    # add a feature
    fet = QgsFeature()
    geometry = QgsGeometry.fromPolygonXY([points])
    fet.setGeometry(geometry)
    fet.setAttributes([fet_name,label])
    pr.addFeatures([fet])

# commit to stop editing the layer
vl.commitChanges()

# update layer's extent when new features have been added
# because change of extent in provider is not propagated to the layer
vl.updateExtents()

myDir = QgsProject.instance().readPath("./")
file_name = 'Distance Buffers' + '.shp'
ShapefileDir = myDir + "/Shapefiles/" + file_name

_writer = QgsVectorFileWriter.writeAsVectorFormat(vl, ShapefileDir, "utf-8", driverName="ESRI Shapefile")

# add layer to the legend
name = 'Distance Buffers'
BufferShp = QgsVectorLayer(ShapefileDir,name, 'ogr')
QgsProject.instance().addMapLayer(BufferShp)

# change active layer
lyr = QgsProject.instance().mapLayersByName(name)[0]
iface.setActiveLayer(lyr)
buffer_lyr = iface.activeLayer()

# load preset qgis style file
buffer_lyr.loadNamedStyle("W:/2. SGER-Economics/c. Project Resources/8. GIS/QGIS Style File/Buffer.qml")
buffer_lyr.triggerRepaint()

I have noticed a few strange behaviors:

  1. When I 'Add Script to Toolbox', it immediately tries to run the script, rather than just updating the toolbox to include the selected script.

  2. After I run it successfully for the first time, I see that the script is now added to my toolbox. However, when I try to run it again, nothing happens. To run it I have to manually open the script in the Processing Script Editor, then Run Script.

  3. After the script is added, whenever I start a new instance of QGIS, I get an error message as such:

An error has occurred while executing Python code:

AttributeError: 'NoneType' object has no attribute 'selectedFeatures' Traceback (most recent call last): File "C:/PROGRA~1/QGIS3~1.4/apps/qgis-ltr/./python/plugins\processing\script\ScriptAlgorithmProvider.py", line 111, in loadAlgorithms alg = ScriptUtils.loadAlgorithm(moduleName, filePath) File "C:/PROGRA~1/QGIS3~1.4/apps/qgis-ltr/./python/plugins\processing\script\ScriptUtils.py", line 68, in loadAlgorithm spec.loader.exec_module(module) File "", line 728, in exec_module File "", line 219, in _call_with_frames_removed File "\file05\Production\2. SGER-Economics\c. Project Resources\8. GIS\QGIS Processing Scripts\Buffer_QGIS3.py", line 6, in geom = iface.activeLayer().selectedFeatures()[0].geometry() AttributeError: 'NoneType' object has no attribute 'selectedFeatures'

I assume all of this happens because for some reason QGIS is trying to run my script on its own whenever it opens. Is there something wrong with my script or is this a bug with the new QGIS?

5

There is a fairly rigid structure for creating a processing script for the QGIS processing tool box, the basis of which is sub-classing and creating an instance of the QgsProcessingAlgorithm class.

In addition to the QGIS3 processing script template by @underdark, there is an excellent tutorial by @spatialthoughts, "Writing Python Scripts for Processing Framework", which has recently been updated for QGIS3.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.