I figured out that besides from the python editor within QGIS, the layers that I'm creating with a Processing Toolbox are not saved and displayed in my .qgs projects.
--> see image: 1) what I get from running a similar script in the python editor (what I want to have) and 2) what I get (no rendering but layer paths are stored in the .qgs project
Here are the steps I follow:
In the processing toolbox, the user gives me the path of the data directory, a path to an excel file and two integer numbers (simulation number start and end) --> THERE ARE NO INPUT layers!!
In my "def processAlgorithm" I make a loop over the simulation numbers. For each loop, I
- Create a .qgs project
- Load 2 rasters and 1 vector layer
- Reclassify the rasters (with saga:reclassifyvaluessimple)
- Save the two reclassified raster and the vector layer to .qgs project
My .qgs projects are saved but the layers do not display! what is wrong? Something with my "QgsProcessingOutputMultipleLayers"? do I have to create a sink?
Here is my code so far:
from PyQt5.QtGui import *
from PyQt5.QtCore import QCoreApplication, QFileInfo, QSettings
from PyQt5.QtWidgets import QApplication
from qgis.utils import iface
from qgis.PyQt import QtGui
from qgis.core import (QgsProcessing,
QgsApplication,
QgsProcessingException,
QgsProcessingAlgorithm,
QgsProcessingParameterString,
QgsProcessingParameterFile,
QgsProcessingParameterNumber,
QgsRasterLayer,
QgsVectorLayer,
QgsProject,
QgsCoordinateReferenceSystem,
QgsPrintLayout,
QgsSingleBandPseudoColorRenderer,
QgsColorRampShader,
QgsRasterShader,
QgsProcessingOutputDefinition,
QgsProcessingOutputMultipleLayers,
QgsProcessingParameterVectorDestination)
import processing
import os
import xlrd
import shutil
class RAMMSResultstoMap(QgsProcessingAlgorithm):
### ALREADY-MADE DEFINITIONS
INPUT_DIR = 'INPUT_DIR'
INPUT_EXCEL = 'INPUT_EXCEL'
START_NBR = 'START_NBR'
END_NBR = 'END_NBR'
OUTPUT_LAYERS = 'OUTPUT_LAYERS'
def __init__(self):
super().__init__()
def tr(self, string):
return QCoreApplication.translate('Processing', string)
def createInstance(self):
return RAMMSResultstoMap()
def name(self):
return 'pyscript'
def displayName(self):
return self.tr('GetMap')
def group(self):
return self.tr('Scripts for myself')
def groupId(self):
return 'ramms'
def shortHelpString(self):
return self.tr("This script will generate .pdfs automatically from the RAMMS simulations' results")
def initAlgorithm(self, config=None):
self.addParameter(
QgsProcessingParameterString(
self.INPUT_DIR,
self.tr('RAMMS Project path')
)
)
self.addParameter(
QgsProcessingParameterFile(
self.INPUT_EXCEL,
self.tr('RAMMS Excel path')
)
)
self.addParameter(
QgsProcessingParameterNumber(
self.START_NBR,
self.tr('Startindex')
)
)
self.addParameter(
QgsProcessingParameterNumber(
self.END_NBR,
self.tr('Stopindex')
)
)
self.addOutput(
QgsProcessingOutputMultipleLayers(
self.OUTPUT_LAYERS,
self.tr('')
)
)
### START OF PROCESSING
def processAlgorithm(self, parameters, context, feedback):
"""
Here is where the processing itself takes place.
"""
## Definitions taking place in the processAlgorithm
# read excel sheet
def readExcelSheet(path, start, end):
workbook = xlrd.open_workbook(path)
worksheet = workbook.sheet_by_name('Tabelle1')
worksheet = workbook.sheet_by_index(0)
# Get additional information
project_gemeinde = worksheet.cell(2, 1).value
project_date = worksheet.cell(0, 18).value
project_author = worksheet.cell(1, 18).value
project_number = worksheet.cell(0, 2).value
# Get table values needed
if start == end:
start = start - 1
table_selected_values = [[worksheet.cell_value(r, c) for c in range(23)] for r in range(start+6,end+6)]
table_infos = [project_gemeinde, project_date, project_author, project_number]
return table_infos, table_selected_values
# read anriss shp
def listAnrissgebiete(path):
anriss_filelist = os.listdir(path)
anriss_shplist = []
for i in anriss_filelist:
if i.endswith(".shp"):
anriss_shplist.append(path + "\\" + i)
return anriss_shplist
# Retrieve input parameters
input_dir = self.parameterAsString(
parameters,
self.INPUT_DIR,
context
)
input_excel = self.parameterAsFile(
parameters,
self.INPUT_EXCEL
context
)
start_nbr = self.parameterAsInt(
parameters,
self.START_NBR,
context
)
end_nbr = self.parameterAsInt(
parameters,
self.END_NBR,
context
)
# Get/retrieve paths and variable
anriss_folder = os.path.dirname(input_dir) + "\\Anrissgebiete"
main_result_folder = os.path.dirname(input_dir) + "\\Resultate"
# create specific result folder
result_folder = main_result_folder + "\\" + os.path.basename(input_dir)
if os.path.isdir(result_folder): # if result folder already exists, remove it
shutil.rmtree(result_folder)
os.mkdir(result_folder)
# Make selection of the .asc files
proc_ramms_folder_list = os.listdir(input_dir)
maxHeight_list_path = []; maxVelocity_list_path = []
maxHeight_list_name = []; maxVelocity_list_name = []
for i in proc_ramms_folder_list:
if "MaxHeight" in i and i.endswith('.asc'):
maxHeight_list_path.append(input_dir + "\\" + i)
maxHeight_list_name.append(i[0:-4]) # takes out the extension from the name
if "MaxVelocity" in i and i.endswith('.asc'):
maxVelocity_list_path.append(input_dir + "\\" + i)
maxVelocity_list_name.append(i[0:-4])
# Import excel file
table_info, table_values = readExcelSheet(input_excel, start_nbr, end_nbr)
project_nbr = table_info[3] # e.g. A10061
# Load anriss zones
anriss_shp_list = listAnrissgebiete(anriss_folder)
# Start loop over all .asc files
for i in range(len(table_values)):
# create new qgis project
processing_name = str(table_values[i][13])
anriss_name = table_values[i][1]
qgis_project_name = result_folder + "\\" + processing_name + ".qgs"
if os.path.isfile(qgis_project_name): # if .qgs project already exists, remove it (overwrites)
os.remove(qgis_project_name)
# create project instance
project = QgsProject.instance()
project.setCrs(QgsCoordinateReferenceSystem(2056))
project.setFileName(qgis_project_name)
project.write() # allows modification of the project
output_layers = []
# load rasters (velocity and height)
r_height_asc = [x for x in maxHeight_list_path if anriss_name in x][0]
r_height_name = [x for x in maxHeight_list_name if anriss_name in x][0]
r_velocity_asc = [x for x in maxVelocity_list_path if anriss_name in x][0]
r_velocity_name = [x for x in maxVelocity_list_name if anriss_name in x][0]
#iface.mainWindow().blockSignals(True) # block pop-up window in .qgs
# raster 1 (height)
rlayer1 = QgsRasterLayer(r_height_asc, r_height_name)
rlayer1.setCrs(QgsCoordinateReferenceSystem(2056))
if not rlayer1.isValid():
print("Height raster failed to load!")
# Reclassify raster
out_rl1 = result_folder + "\\" + r_height_name + ".sdat"
reclass_raster = processing.run("saga:reclassifyvaluessimple", {'GRID_IN':rlayer1,
'METHOD':2,
'LOOKUP':[0,0.3,0,0.3,0.5,1,0.5,1.0,2,1.0,2.0,3,2.0,1000.0,4],
'GRID_OUT':out_rl1})
project.removeMapLayer(rlayer1)
rlayer1_recl = QgsRasterLayer(out_rl1, "Max. Fliesshöhe (Rohdaten)")
rlayer1_recl .setCrs(QgsCoordinateReferenceSystem(2056))
# change raster 1 symbology
raster_shader = QgsColorRampShader()
raster_shader.setColorRampType(QgsColorRampShader.Exact)
colors_list = [
QgsColorRampShader.ColorRampItem(1, QColor.fromRgb(204, 219, 255), "0.3-0.5m"),
QgsColorRampShader.ColorRampItem(2, QColor.fromRgb(102, 178, 255), "0.5-1.0m"),
QgsColorRampShader.ColorRampItem(3, QColor.fromRgb(0, 128, 255), "1.0-2.0m"),
QgsColorRampShader.ColorRampItem(4, QColor.fromRgb(0, 0, 153), ">2m")]
raster_shader.setColorRampItemList(colors_list)
shader = QgsRasterShader()
shader.setRasterShaderFunction(raster_shader)
renderer = QgsSingleBandPseudoColorRenderer(rlayer1_recl.dataProvider(), 1, shader)
rlayer1_recl.setRenderer(renderer)
rlayer1_recl.triggerRepaint()
project.addMapLayer(rlayer1_recl)
output_layers.append(out_rl1)
# raster 2 (velocity)
rlayer2 = QgsRasterLayer(r_velocity_asc, r_velocity_name)
rlayer2.setCrs(QgsCoordinateReferenceSystem(2056))
if not rlayer2.isValid():
print("Velocity raster failed to load!")
# Reclassify raster
out_rl2 = result_folder + "\\" + r_velocity_name + ".sdat"
reclass_raster = processing.run("saga:reclassifyvaluessimple", {'GRID_IN':rlayer2,
'METHOD':2,
'LOOKUP':[0.0,1.0,0,1.0,3.0,1,3.0,10.0,2,10.0,20.0,3,20.0,1000.0,4],
'GRID_OUT':out_rl2})
project.removeMapLayer(rlayer2)
rlayer2_recl = QgsRasterLayer(out_rl2, "Max. Fliessgeschwindigkeit (Rohdaten)")
rlayer2_recl.setCrs(QgsCoordinateReferenceSystem(2056))
# change raster 2 symbology
raster_shader = QgsColorRampShader()
raster_shader.setColorRampType(QgsColorRampShader.Exact)
colors_list = [
QgsColorRampShader.ColorRampItem(1, QColor.fromRgb(255, 204, 255), "1.0-3.0m/s"),
QgsColorRampShader.ColorRampItem(2, QColor.fromRgb(255, 102, 255), "3.0-10.0m/s"),
QgsColorRampShader.ColorRampItem(3, QColor.fromRgb(204, 0, 204), "10.0-20.0m/s"),
QgsColorRampShader.ColorRampItem(4, QColor.fromRgb(102, 0, 102), ">20m/s")]
raster_shader.setColorRampItemList(colors_list)
shader = QgsRasterShader()
shader.setRasterShaderFunction(raster_shader)
renderer = QgsSingleBandPseudoColorRenderer(rlayer2_recl.dataProvider(), 1, shader)
rlayer2_recl.setRenderer(renderer)
rlayer2_recl.triggerRepaint()
project.addMapLayer(rlayer2_recl)
output_layers.append(out_rl1)
# Load anrissgebiet
anriss_shp = [x for x in anriss_shp_list if anriss_name in x][0]
#iface.mainWindow().blockSignals(True)
shplayer = QgsVectorLayer(anriss_shp, anriss_name, "ogr")
shplayer.setCrs(QgsCoordinateReferenceSystem(2056))
if not shplayer.isValid():
print("Anriss .shp failed to load!")
project.addMapLayer(shplayer)
output_layers.append(anriss_shp)
# Save and close qgis document
#iface.mainWindow().blockSignals(False)
project.write(qgis_project_name)
# clear current qgis project
project.clear()
return {self.OUTPUT_LAYERS: output_layers}
project.write()
four times in your script or could you use it once at the end?iface.mainWindow().blockSignals(True)
as this tends to block all signals. I'm guessing you're using this to stop the CRS window from showing? Try removing these lines and add the layer usingrlayer1 = QgsRasterLayer(path, 'someName')
;rlayer1.setCrs(...)
;QgsProject.instance().addMapLayer(rlayer1)