1

I've created a processing script in QGIS 3, and although my output layer has shows a feature count greater than zero when using the feedback command, the resulting feature layer that appears in QGIS has no features. What am I doing wrong?

# -*- coding: utf-8 -*-
##source_layer=vector
##output_layer=output vector

from PyQt5.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
                       QgsFeatureSink,
                       QgsProcessingException,
                       QgsProcessingAlgorithm,
                       QgsProcessingParameterFeatureSource,
                       QgsProcessingParameterFeatureSink)
import processing


class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):

    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'

    def tr(self, string):
        return QCoreApplication.translate('Processing', string)

    def createInstance(self):
        return ExampleProcessingAlgorithm()

    def name(self):
        return 'myscript'

    def displayName(self):
        return self.tr('My Script')

    def group(self):
        return self.tr('Example scripts')

    def groupId(self):
        return 'examplescripts'

    def shortHelpString(self):
        return self.tr("Example algorithm short description")

    def initAlgorithm(self, config=None):
        self.addParameter(
            QgsProcessingParameterFeatureSource(
                self.INPUT,
                self.tr('Input layer'),
                [QgsProcessing.TypeVectorAnyGeometry]
            )
        )

        self.addParameter(
            QgsProcessingParameterFeatureSink(
                self.OUTPUT,
                self.tr('Output layer')
            )
        )

    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsVectorLayer(
            parameters,
            self.INPUT,
            context
        )

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

        (sink, dest_id) = self.parameterAsSink(
            parameters,
            self.OUTPUT,
            context,
            source.fields(),
            source.wkbType(),
            source.sourceCrs()
        )

        feedback.pushInfo('CRS is {}'.format(source.sourceCrs().authid()))

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


        sink=processing.run("native:buffer", {
            'INPUT': source,
            'DISTANCE': -4.0,
            'SEGMENTS': 5,
            'END_CAP_STYLE': 0,
            'JOIN_STYLE': 0,
            'MITER_LIMIT': 2,
            'DISSOLVE': False,
            'OUTPUT': 'memory:'
        }, context=context, feedback=feedback)['OUTPUT']

        feedback.pushInfo('sink output number of features is {}'.format(sink.featureCount()))

        results = {}
        results[self.OUTPUT] = sink
        return results

Subsequently, I've tried changing the last section to:

    bufferedLayer=processing.run("native:buffer", {
        'INPUT': source,
        'DISTANCE': -4.0,
        'SEGMENTS': 5,
        'END_CAP_STYLE': 0,
        'JOIN_STYLE': 0,
        'MITER_LIMIT': 2,
        'DISSOLVE': False,
        'OUTPUT': parameters['OUTPUT']
    }, context=context, feedback=feedback)['OUTPUT']
    feedback.pushInfo('sink output number of features is {}'.format(bufferedLayer.featureCount()))

    return {self.OUTPUT: bufferedLayer}

The function down gives the gives an error when it runs. Here is the output log for the function:

Processing algorithm…
Algorithm 'My Script' starting…
Input parameters:
{'INPUT':'C:/GIS/VBS/map_nsc_geotypical_ne_europe/map_nsc_geotypical_ne_europe_shared/source/multimap/tiles_3x3/mapframes/gce_3x3_001_001.shp', 'OUTPUT' : 'memory:' }
CRS is EPSG:32634
Results: {'OUTPUT': 'output_7cd8f3b7_6e2b_457b_be6b_da9c71439756'} sink output number of features is 1 Execution completed in 0.03 seconds Results: {'OUTPUT': }

Loading resulting layers
The following layers were not correctly generated.<ul><li>output_7cd8f3b7_6e2b_457b_be6b_da9c71439756</li></ul>You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.

I've tried following Jochen's suggestion of using an output rather than a parameter. By doing this the script window changes from this: enter image description here to this, it no longer has the option to specify the output layer: enter image description here

Running the script also causes QGIS to crash :/

  • I think you have created a processing script in QGIS 3, not in ARCGIS 3, which has long since departed... – Jochen Schwarze Dec 10 '18 at 15:11
  • Haha! Good spot - I've corrected. Thanks – M Bentley Dec 10 '18 at 15:50
  • @M Bentley Did 2nd try solve your problem? – Jochen Schwarze Dec 20 '18 at 8:54
  • @jochen-schwarze - That did work, thank you – M Bentley Dec 21 '18 at 9:32
0

2nd try. After some reasearching I found that the key problem seems to be that you first defined sink

(sink, dest_id) = self.parameterAsSink( ...

and later on overwrite it with the result of processing.run...

sink=processing.run("native:buffer", { ...

I tried the following which worked for me:

#create a temporary layer as a processing result
lyr = processing.run("native:buffer", {
        'INPUT': source,
        'DISTANCE': 40,
        'SEGMENTS': 5,
        'END_CAP_STYLE': 0,
        'JOIN_STYLE': 0,
        'MITER_LIMIT': 2,
        'DISSOLVE': False,
        'OUTPUT': 'memory:'
    }, context=context, feedback=feedback)['OUTPUT']

    feedback.pushInfo('sink output number of features is {}'.format(lyr.featureCount()))

# and then copy the content of the temporary processing result into the output sink    
for f in lyr.getFeatures():
    sink.addFeature(f)

Note that when you define the output sink as follows

(sink, dest_id) = self.parameterAsSink(
        parameters,
        self.OUTPUT,
        context,
        source.fields(),
        source.wkbType(),
        source.sourceCrs()
    )

you are restricted to the geometry type of the source layer (source.wkbType()), which may cause problems (crash) when you try to buffer e.g. a point layer.

But with the mentioned slight alterations your script works:

enter image description here

  • 1
    Yes this works for me too! Thank you. I had avoided iterating through the features because I thought this could be computationally heavy. I guess I don't entirely understand what the outputSink is - it obviously has a specific purpose. – M Bentley Dec 21 '18 at 9:28
  • Your welcome! A great way of saying 'Thank you' is to vote for and accept an answer ;-) – Jochen Schwarze Dec 21 '18 at 9:30
0

I think, in the initAlgorithm(...) method you have defined your OUTPUT parameter as an input.

Try replacing

self.addParameter(
        QgsProcessingParameterFeatureSink(
            self.OUTPUT,
            self.tr('Output layer')
        )
    )

with

self.addOutput(
    QgsProcessingOutputVectorLayer(
        self.OUTPUT,
        self.tr('Output layer')
    )
)

The OUTPUT parameters allways start with QgsProcessingOutput..., cp. https://qgis.org/api/classQgsProcessingOutputDefinition.html

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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