2

I'M writing an own QgsProcessing Algorithm and I want to give the output layer in the registry a custom name instead of the default "Output layer". I want to do that during processAlgorithm(), because I'd like to name the output after an input layer, adding a fixed name prefix.

I tried the setOutputLayerName() from the class QgsProcessingContext::LayerDetails, but it doesn't change the name of the output. The example below is the "template" that the QGIS processing toolbox suggests for algorithm writing. Note the last third last and second last rows of the code, where I tried out my approach.

from qgis.PyQt.QtCore import QCoreApplication
from qgis.core import (QgsProcessing,
 QgsVectorLayer,
 QgsFeatureSink,
 QgsProcessingException,
 QgsProcessingAlgorithm,
 QgsProcessingParameterFeatureSource,
 QgsProcessingParameterFeatureSink)
from qgis 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.parameterAsSource(
 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()
 )
 # Send some information to the user
 feedback.pushInfo('CRS is {}'.format(source.sourceCrs().authid()))
 if sink is None:
 raise QgsProcessingException(self.invalidSinkError(parameters, self.OUTPUT))
 
 total = 100.0 / source.featureCount() if source.featureCount() else 0
 features = source.getFeatures()
 for current, feature in enumerate(features):
 # Stop the algorithm if cancel button has been clicked
 if feedback.isCanceled():
 break
 # Add a feature in the sink
 sink.addFeature(feature, QgsFeatureSink.FastInsert)
 # Update the progress bar
 feedback.setProgress(int(current * total))
 if False:
 buffered_layer = processing.run("native:buffer", {
 'INPUT': dest_id,
 'DISTANCE': 1.5,
 'SEGMENTS': 5,
 'END_CAP_STYLE': 0,
 'JOIN_STYLE': 0,
 'MITER_LIMIT': 2,
 'DISSOLVE': False,
 'OUTPUT': 'memory:'
 }, context=context, feedback=feedback)['OUTPUT']
 layer = QgsVectorLayer(baseName="My Output") # Create an empty layer for output naming
 context.layerToLoadOnCompletionDetails(dest_id).setOutputLayerName(layer) # Add this name to the output context
 return {self.OUTPUT: dest_id}
Kadir Şahbaz
78.6k57 gold badges260 silver badges407 bronze badges
asked Oct 7, 2020 at 13:25

2 Answers 2

6

You need to use the QgsProcessingLayerPostProcessorInterface.postProcessLayer method to rename the layer after it has been added to the project. Using the QgsMapLayer.setName method has no effect. To use this, define a new class:

class Renamer (QgsProcessingLayerPostProcessorInterface):
 def __init__(self, layer_name):
 self.name = layer_name
 super().__init__()
 
 def postProcessLayer(self, layer, context, feedback):
 layer.setName(self.name)

Then in your code, create an instance of the class and attach it to the output layer:

 global renamer
 renamer = Renamer('DiffBuf')
 context.layerToLoadOnCompletionDetails(self.dest_id).setPostProcessor(renamer)

It is essential that you declare the variable holding the class as global, otherwise this will not work. self.dest_id in the code is the value of the second return value of parameterAsSink.

answered Jan 21, 2021 at 16:07
0
4

I figure out you can just do :

layer_details = context.layerToLoadOnCompletionDetails(dest_id)
layer_details.name = "My output"

To remove the error in log (if the layer is not loaded) it's possible to do this :

if context.willLoadLayerOnCompletion(dest_id):
 layer_details = context.layerToLoadOnCompletionDetails(dest_id)
 layer_details.name = "My output"
answered May 11, 2023 at 10:30
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.