3

I've written a processing script using pyqgis 3.4 which works. The next step I would like to achieve is to load openstreetmaps as the base map from within the processing script. I can do so easily from the Python Console, but that is not how I want to go about this task. I have tried three different ways to load the raster layers, and can't find or think of any others. The code doesn't give errors, but also doesn't load openstreetmap.

from qgis.PyQt.QtCore import QCoreApplication, QVariant
from qgis.core import (QgsProcessing, QgsProcessingAlgorithm, 
QgsProcessingParameterRasterLayer,QgsProcessingParameterNumber, 
QgsProcessingParameterRasterDestination, QgsRasterLayer, QgsProject)

import processing

class RasterAlg(QgsProcessingAlgorithm):
    OUTPUT_RASTER_A = 'OUTPUT_RASTER_A'

    def __init__(self):
        super().__init__()

    def name(self):
        return "RasterAlg"

    def tr(self, text):
        return QCoreApplication.translate("RasterAlg", text)

    def displayName(self):
        return self.tr("RasterAlg script")

    def group(self):
        return self.tr("RasterAlgs")

    def groupId(self):
        return "RasterAlgs"

    def shortHelpString(self):
        return self.tr("RasterAlg script without logic")

    def helpUrl(self):
        return "https://qgis.org"

    def createInstance(self):
        return type(self)()

    def initAlgorithm(self, config=None):

        self.addParameter(QgsProcessingParameterRasterDestination(
            self.OUTPUT_RASTER_A,
            self.tr("Output Raster A")
            ))

    def processAlgorithm(self, parameters, context, feedback):

        urlWithParams = 'type=xyz&url=https://a.tile.openstreetmap.org/%7Bz%7D/%7Bx%7D/%7By%7D.png&zmax=19&zmin=0&crs=EPSG4326'
        rlayer = QgsRasterLayer(urlWithParams, 'OpenStreetMap', 'wms')
        QgsProject.instance().addMapLayer(rlayer)

        view = QgsRasterLayer(urlWithParams, 'OpenStreetMap2','gdal')
        QgsProject.instance().addMapLayer(view)


        results = {}
        results[self.OUTPUT_RASTER_A] = rlayer

        return results```
PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Andrew
  • 67
  • 5

2 Answers2

2

You mustn't use QgsProject.instance() in a processing script. The project is given from the context you are using. You have the context.project() property for that.

If you really want to add the layer from within the processing script :

    def initAlgorithm(self, config=None):
        # Add your other parameters and output parameters

        self.addOutput(
            QgsProcessingOutputMultipleLayers(
                self.OUTPUT_LAYERS,
                self.tr('Output layers')
            )
        )

    def processAlgorithm(self, parameters, context, feedback):

        # At the end of the processAlgorithmn
        # Add the layer to the project

        output_layers = []
        output_layers.append(layer)
        context.temporaryLayerStore().addMapLayer(layer)
        context.addLayerToLoadOnCompletion(
            layer.id(),
            QgsProcessingContext.LayerDetails(
                'layer name',
                context.project(),
                self.OUTPUT_LAYERS
            )
        )

        return {self.OUTPUT_LAYERS: output_layers}
etrimaille
  • 7,240
  • 34
  • 47
0

Normally you can't add a mapLayer from a processing script, because the processing script runs asynchron/"in parallel" with qgis and can't invoce a new map layer. This is also discussed in Load layer in QGIS legend from Processing script [QGIS 3]

Andreas Müller
  • 2,622
  • 13
  • 20
  • It's possible to add layers from a Processing algorithm. Even without the flag NoThreading, CF my answer above. – etrimaille Nov 29 '19 at 11:06