7

I have a weird problem. I'm writing a Processing standalone plugin in QGIS 3 (current master, 3.1).

In the main algorithm I have to create some intermediate layers (mostly raster) with GRASS and SAGA provider, no problem so far. For example here the snippet of r.watershed:

viewshed = processing.run('grass7:r.viewshed', {
    'input': raster,
    'coordinates': coordStr,
    'observer_elevation': 0,
    'target_elevation': 0,
    'max_distance': Visibility_Distance,
    'refraction_coeff': 0.14286,
    'memory': 500,
    '-c':False,
    '-r':False,
    '-b':False,
    '-e':False,
    'output':os.path.join(Results, 'my_output.tif'),
    'GRASS_REGION_PARAMETER': tr_extent,
    'GRASS_REGION_CELLSIZE_PARAMETER':0,
    'GRASS_RASTER_FORMAT_OPT':'',
    'GRASS_RASTER_FORMAT_META':''

})

but then I cannot load the resulting layer in the legend, even if it is correctly created and I can load it by hand.

Here what I'm trying to do:

view = QgsRasterLayer(viewshed['output'], 'my_output','gdal')
QgsProject.instance().addMapLayer(view)

I don't get any error from the console.

The exact same syntax works in a single script written in the Python editor of QGIS.

Any clue?

Kadir Şahbaz
  • 76,800
  • 56
  • 247
  • 389
matteo
  • 3,304
  • 1
  • 23
  • 47

2 Answers2

6

I used that way to change layer order while processing. As I know, normally you can't add layer to legend while processing in QGIS 3 unlike QGIS 2.

Try that. But it's risky according to this post.

# add this method to your algorithm class.
def flags(self):
    return super().flags() | QgsProcessingAlgorithm.FlagNoThreading

and

# add last two lines (feedback and context parameters) to your 'run' method
viewshed = processing.run('grass7:r.viewshed', {
    'input': raster,
    'coordinates': coordStr,
    'observer_elevation': 0,
    'target_elevation': 0,
    'max_distance': Visibility_Distance,
    'refraction_coeff': 0.14286,
    'memory': 500,
    '-c':False,
    '-r':False,
    '-b':False,
    '-e':False,
    'output':os.path.join(Results, 'my_output.tif'),
    'GRASS_REGION_PARAMETER': tr_extent,
    'GRASS_REGION_CELLSIZE_PARAMETER':0,
    'GRASS_RASTER_FORMAT_OPT':'',
    'GRASS_RASTER_FORMAT_META':''
},
feedback=feedback, # without these two lines 
context=context)   # QGIS may crash

# And then, try to add layer to map.
view = QgsRasterLayer(viewshed['output'], 'my_output','gdal')
QgsProject.instance().addMapLayer(view)
Kadir Şahbaz
  • 76,800
  • 56
  • 247
  • 389
  • thanks! I missed that! Did you make some experiments with the method that will be available in 3.2 (QgsProcessingLayerPostProcessorInterface)? – matteo Apr 23 '18 at 16:43
1

You can also do it without having to run your script inside the main thread, which works but may not be ideal.

# And then, try to add layer to map.
view = QgsRasterLayer(viewshed['output'], 'my_output','gdal')
context.temporaryLayerStore().addMapLayer(view)
context.addLayerToLoadOnCompletion(view.id(), QgsProcessingContext.LayerDetails("", QgsProject.instance(), ""))
  • Just the line seems to be enough for me, no need for a QgsRasterLayer instance or adding it to the store: context.addLayerToLoadOnCompletion(visibility_viewshed["OUTPUT"], QgsProcessingContext.LayerDetails("", QgsProject.instance())) – bugmenot123 Apr 06 '23 at 16:31