4

How can I import a .qml style from a file and apply it to a sink?

In QGIS 2.18, I used something like that script:

output=QgsVectorLayer ('Point?crs=EPSG:2154','output', 'memory')
path_style='./path/to/style.qml'
output.loadNamedStyle(path_style)
output.triggerRepaint()

But when I tried it on anita graser's example of QGIS3 script, .loadNamedStyle() wouldn't work on the sink OUTPUT:

from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsField, QgsFeature, QgsFeatureSink, QgsFeatureRequest, QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink)

class ExAlgo(QgsProcessingAlgorithm):
    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'
    def __init__(self):
        super().__init__()
    def name(self):
        return "exalgo"
    def tr(self, text):
        return QCoreApplication.translate("exalgo", text)
    def createInstance(self):
        return type(self)()

    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"),
            QgsProcessing.TypeVectorAnyGeometry))

    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               source.fields(), source.wkbType(), source.sourceCrs())

        features = source.getFeatures(QgsFeatureRequest())
        for feat in features:
            out_feat = QgsFeature()
            out_feat.setGeometry(feat.geometry())
            out_feat.setAttributes(feat.attributes())
            sink.addFeature(out_feat, QgsFeatureSink.FastInsert)

        # --------------------the part that doesn't work:
        path_style='./path/to/style.qml'
        sink.loadNamedStyle(path_style)
        sink.triggerRepaint()
        #--------------------

        return {self.OUTPUT: dest_id}

Is there a simple way to load and apply a style in the new QGIS Processing?

LeoC
  • 545
  • 2
  • 8
  • you need call def postProcessAlgorithm method, check this sample for add a style https://github.com/olivierdalang/travel_time_platform_plugin/blob/14d3dd70d3a4ef85d9fb9c8634d1ce06a4b498f5/algorithms.py#L391 – Fran Raga Apr 19 '19 at 17:49

2 Answers2

4

you need call def postProcessAlgorithm method.I add an example of how the code should be,

    def postProcessAlgorithm(self, context, feedback):
        """
        PostProcessing to define the Symbology
        """
        output = QgsProcessingUtils.mapLayerFromString(self.dest_id, context)
        path = ='./path/to/style.qml'
        output.loadNamedStyle(path)
        output.triggerRepaint()
        return {self.OUTPUT: self.dest_id}
Fran Raga
  • 7,838
  • 3
  • 26
  • 47
  • Simply pasting your code didn't work however when I read your sample code in your first answer, line 521" to get hold of the layer in post processing" I finally understood. – LeoC May 07 '19 at 15:26
  • does it still work for QGIS 3.16? It seems to no longer work for me or i got something else wrong – miraculix Mar 18 '22 at 18:52
2

Thank you @Fran Raga for your answer, the example you gave didn't work at first but by reading the sample code you provided in your first comment I finnaly succeded here's what works for me:

from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsField, QgsFeature, QgsFeatureSink, QgsFeatureRequest, QgsProcessing, QgsProcessingAlgorithm, QgsProcessingParameterFeatureSource, QgsProcessingParameterFeatureSink)

class ExAlgo(QgsProcessingAlgorithm):
    INPUT = 'INPUT'
    OUTPUT = 'OUTPUT'
    def __init__(self):
        super().__init__()
    def name(self):
        return "exalgo"
    def tr(self, text):
        return QCoreApplication.translate("exalgo", text)
    def createInstance(self):
        return type(self)()

    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"),
            QgsProcessing.TypeVectorAnyGeometry))

    def processAlgorithm(self, parameters, context, feedback):
        source = self.parameterAsSource(parameters, self.INPUT, context)
        (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT, context,
                                               source.fields(), source.wkbType(), source.sourceCrs())

        features = source.getFeatures(QgsFeatureRequest())
        for feat in features:
            out_feat = QgsFeature()
            out_feat.setGeometry(feat.geometry())
            out_feat.setAttributes(feat.attributes())
            sink.addFeature(out_feat, QgsFeatureSink.FastInsert)

        # to get hold of the layer in post processing:
        self.dest_id=dest_id

        return {self.OUTPUT: dest_id}

    #Changes suggested by Fran Raga:   
    def postProcessAlgorithm(self, context, feedback):
        output = QgsProcessingUtils.mapLayerFromString(self.dest_id, context)
        path='./path/to/style.qml'
        output.loadNamedStyle(path)
        output.triggerRepaint()
        return {self.OUTPUT: self.dest_id}
LeoC
  • 545
  • 2
  • 8