2

I've created a processing script in QGIS 3.10, but can't seem to achieve the last step of styling the processed layer. My script follows the new easy processing script format that have come back since version 3.6.

I've referenced QGIS 3.4, how to add .qml style to sink in processing, but my script doesn't seem to run the postProcessAlgorithm bit below.

from math import *
from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.processing import alg
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsFeature,
                       QgsVectorLayer,
                       QgsGeometry,
                       QgsPointXY,
                       QgsField,
                       QgsFields,
                       QgsWkbTypes,
                       QgsProject,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink,
                       QgsProcessingParameterField,
                       QgsVectorFileWriter
                       )
from qgis.utils import iface
import processing

@alg(name="distance_buffer", label=alg.tr("Distance Buffer"), group="base", group_label=alg.tr("base"))
@alg.input(type=alg.SOURCE, name="INPUT", label="Input layer")
@alg.input(type=alg.SINK, name="OUTPUT", label="Distance Buffers")
@alg.input(type=alg.FILE, name='STYLEFILE', label='Style file', default='C:/Desktop/Buffer.qml')

def processAlgorithm(instance, parameters, context, feedback, inputs):
    """
    Create accurate distance buffers with reprojection.
    """
    source = instance.parameterAsSource(parameters, "INPUT", context)

    if source is None:
        raise QgsProcessingException(instance.invalidSourceError(parameters, "INPUT"))

    fields = QgsFields()
    fields.append(QgsField("Distance", QVariant.Int))
    fields.append(QgsField("Label", QVariant.String))

    (sink, dest_id) = instance.parameterAsSink(parameters, "OUTPUT", context,
                                              fields,
                                              QgsWkbTypes.Polygon,
                                              source.sourceCrs()
                                          )

    if sink is None:
        raise QgsProcessingException(instance.invalidSinkError(parameters, "OUTPUT"))

    total = 100.0 / source.featureCount() if source.featureCount() else 0
    selection = source.getFeatures()
    for current, feature in enumerate(selection):
        if feedback.isCanceled():
            break
        for select in selection:
            geom = select.geometry()
            start_x = geom.asPoint().x()
            start_y = geom.asPoint().y()
            sides = 64
            radius = 6378137.0 # meters
            distance = [250, 500, 1000, 2000, 3000, 4000, 5000, 10000, 15000, 20000, 25000, 30000, 40000, 50000]
            feedback.pushInfo('Creating layer and adding fields.')
            # Create new layer.
            vl = QgsVectorLayer("Polygon", "Distance Buffers", "memory")
            # Add fields.
            pr = vl.dataProvider()
            pr.addAttributes(fields)
            vl.updateFields()
            for i in range(len(distance)):
                feedback.pushInfo('Creating feature.')
                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))
                    feat_name = str(distance[i])
                    if distance[i] < 1000:
                        label = str(distance[i]) + "m"
                    else:
                        label = str(distance[i]/1000) + "km"
                feedback.pushInfo('Adding feature to layer.')
                # Add calculated features.
                feat = QgsFeature()
                geometry = QgsGeometry.fromPolygonXY([points])
                feat.setGeometry(geometry)
                feat.setAttributes([feat_name,label])
                sink.addFeature(feat, QgsFeatureSink.FastInsert)

        feedback.setProgress(int(current * total))

    return {"OUTPUT": dest_id}

def postProcessAlgorithm(self, context, feedback):
    style = instance.parameterAsString(parameters, "STYLEFILE", context)
    processed_layer = QgsProcessingUtils.mapLayerFromString(dest_id, context)
    processed_layer.loadNamedStyle(style)
    processed_layer.triggerRepaint()
    feedback.pushInfo('Loaded buffer styling.')

    return {"OUTPUT": dest_id}

Has this changed since version 3.6?

2

Figured it out. With the new easy scripting, I simply had to embed the styling step at the end of the processing function:

from math import *
from PyQt5.QtCore import QCoreApplication, QVariant
from qgis.processing import alg
from qgis.core import (QgsProcessing,
                       QgsProcessingUtils,
                       QgsFeatureSink,
                       QgsFeature,
                       QgsVectorLayer,
                       QgsGeometry,
                       QgsPointXY,
                       QgsField,
                       QgsFields,
                       QgsWkbTypes,
                       QgsProject,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink,
                       QgsProcessingParameterField,
                       QgsVectorFileWriter
                       )
from qgis.utils import iface
import processing

@alg(name="distance_buffer", label=alg.tr("Distance Buffer"), group="base", group_label=alg.tr("base"))
@alg.input(type=alg.SOURCE, name="INPUT", label="Input layer")
@alg.input(type=alg.SINK, name="OUTPUT", label="Distance Buffers")
@alg.input(type=alg.FILE, name='STYLEFILE', label='Style file', default='C:/Desktop/Buffer.qml')

def processAlgorithm(instance, parameters, context, feedback, inputs):
    """
    Create accurate distance buffers with reprojection.
    """
    source = instance.parameterAsSource(parameters, "INPUT", context)

    if source is None:
        raise QgsProcessingException(instance.invalidSourceError(parameters, "INPUT"))

    fields = QgsFields()
    fields.append(QgsField("Distance", QVariant.Int))
    fields.append(QgsField("Label", QVariant.String))

    (sink, dest_id) = instance.parameterAsSink(parameters, "OUTPUT", context,
                                              fields,
                                              QgsWkbTypes.Polygon,
                                              source.sourceCrs()
                                          )

    if sink is None:
        raise QgsProcessingException(instance.invalidSinkError(parameters, "OUTPUT"))

    total = 100.0 / source.featureCount() if source.featureCount() else 0
    selection = source.getFeatures()
    for current, feature in enumerate(selection):
        if feedback.isCanceled():
            break
        for select in selection:
            geom = select.geometry()
            start_x = geom.asPoint().x()
            start_y = geom.asPoint().y()
            sides = 64
            radius = 6378137.0 # meters
            distance = [250, 500, 1000, 2000, 3000, 4000, 5000, 10000, 15000, 20000, 25000, 30000, 40000, 50000]
            feedback.pushInfo('Creating layer and adding fields.')
            # Create new layer.
            vl = QgsVectorLayer("Polygon", "Distance Buffers", "memory")
            # Add fields.
            pr = vl.dataProvider()
            pr.addAttributes(fields)
            vl.updateFields()
            for i in range(len(distance)):
                feedback.pushInfo('Creating feature.')
                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))
                    feat_name = str(distance[i])
                    if distance[i] < 1000:
                        label = str(distance[i]) + "m"
                    else:
                        label = str(distance[i]/1000) + "km"
                feedback.pushInfo('Adding feature to layer.')
                # Add calculated features.
                feat = QgsFeature()
                geometry = QgsGeometry.fromPolygonXY([points])
                feat.setGeometry(geometry)
                feat.setAttributes([feat_name,label])
                sink.addFeature(feat, QgsFeatureSink.FastInsert)

        feedback.setProgress(int(current * total))

    style = instance.parameterAsString(parameters, "STYLEFILE", context)
    processed_layer = QgsProcessingUtils.mapLayerFromString(dest_id, context)
    processed_layer.loadNamedStyle(style)
    processed_layer.triggerRepaint()
    feedback.pushInfo('Loaded buffer styling.')

    return {"OUTPUT": dest_id}
| improve this answer | |

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.