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.You can check the 'Log Messages Panel' in QGIS main window to find more information about the execution of the algorithm.
- output_7cd8f3b7_6e2b_457b_be6b_da9c71439756
I've tried following Jochen's suggestion of using an output rather than a parameter. By doing this the script window changes from this:
to this, it no longer has the option to specify the output layer: 
Running the script also causes QGIS to crash :/
Answer
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:

No comments:
Post a Comment