I'm writing some scripts in QGIS 3 to automate processing using a number of the inbuilt algorithms. I'm using memory layers to store the intermediate results of the algorithms. I'm looking for a simple way to persist the layer into the layer list in the project once the algorithms have been executed.
At the moment, the only way I can work out how to persist the final processed layer is to use one of the algorithms (such as native:merge) as a post-processing step. The issue I have is that it adds it the the layer list with the name "merged". I would like to be able to define the name that it gets in the layers list.
I've looked at alternatives such as addMapLayer()
but it doesn't add the layer to the project. In the example below I want the layer to be added with the name "layername".
The script is being added as an algorithm under the processing toolbox.
# -*- coding: utf-8 -*-
from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
QgsFeatureSink,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterFeatureSource,
QgsProcessingParameterFeatureSink,
QgsVectorLayer,
QgsProject)
from qgis import processing
class ExampleProcessingAlgorithm(QgsProcessingAlgorithm):
INPUT1 = 'INPUT1'
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return ExampleProcessingAlgorithm()
def name(self):
return 'testpersistence'
def displayName(self):
return self.tr('Testpersistence')
def group(self):
return self.tr('Example scripts')
def groupId(self):
return 'examplescripts'
def shortHelpString(self):
return self.tr("Testing the script")
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterFeatureSource(
self.INPUT1,
self.tr('Input layer 1'),
[QgsProcessing.TypeVectorAnyGeometry]
)
)
def processAlgorithm(self, parameters, context, feedback):
source1 = self.parameterAsSource(parameters,self.INPUT1,context)
fixgeometries1_result = processing.run(
'native:fixgeometries',
{
'INPUT': parameters['INPUT1'],
'OUTPUT': 'memory:'
},
is_child_algorithm=True,
context=context,
feedback=feedback)
uri = fixgeometries1_result['OUTPUT'].dataProvider().dataSourceUri()
layer1 = QgsVectorLayer(uri,"layername","memory")
QgsProject.instance().addMapLayer(layer1)
return {}
The code fails with an error:
AttributeError: 'str' object has no attribute 'dataProvider'
Best Answer
There are a few problems with your script. Firstly, to define a layer to load on completion, you must an additional parameter of type
QgsProcessingParameterFeatureSink
in theinitAlgorithm()
method.Then, when you call the native fix geometries algorithm inside the
processAlgorithm()
method, the output parameter should be:parameters['OUTPUT']
.That will give you the checkbox in the dialog: 'Open output file after running algorithm'
Renaming the output file is a little more involved. To do this you need to add a Layer Post Processor class and rename the layer inside this class. Then create an instance of this class at the end of the
processAlgorithm()
method and pass it to thesetPostProcessor()
method chained to thelayerToLoadOnCompletionDetails()
method of theQgsProcessingContext
object.Working modified script below (maybe not perfect but it's working!):
The code for the
MyLayerPostProcessor()
class I adapted from a github gist of Nyall Dawson's here.See a gif below showing this script working and loading a renamed layer: