6

I am trying run an exported QGIS model as Python script from Anaconda.

I followed Executing a standalone QGIS python script on Windows 10, and I get no error of modules, when running this I get no error nor output but some warnings of deprecation

import os, sys
# Append QGIS Python library to python search path
sys.path.append(r'C:\Program Files\QGIS 3.6\apps\Python37')
# Append location of DLLs to current system PATH envrionment variable
os.environ['PATH'] += r";C:\Program Files\QGIS 3.6\apps\qgis\python;"
print (os.environ['PATH'])
from qgis.core import QgsProcessing
from qgis.core import QgsProcessingAlgorithm
from qgis.core import QgsProcessingMultiStepFeedback
from qgis.core import QgsProcessingParameterRasterLayer
from qgis.core import QgsProcessingParameterFeatureSink
sys.path.append(r'C:\Program Files\QGIS 3.6\apps\qgis\python\plugins')
import processing
class Trees(QgsProcessingAlgorithm):
 def initAlgorithm(self, config=None):
 self.addParameter(QgsProcessingParameterRasterLayer('dsm', 'DSM', defaultValue="Path/dsm.tif"))
 self.addParameter(QgsProcessingParameterRasterLayer('dtm', 'DTM', defaultValue="Path/dtm.tif"))
 self.addParameter(QgsProcessingParameterRasterLayer('zone', 'Zone', defaultValue="Path/odm_orthophoto.tif"))
 self.addParameter(QgsProcessingParameterFeatureSink('Finaltrees', 'FinalTrees', type=QgsProcessing.TypeVectorAnyGeometry, createByDefault=True, defaultValue='Path/finaltrees.shp'))
 def processAlgorithm(self, parameters, context, model_feedback):
 # Use a multi-step feedback, so that individual child algorithm progress reports are adjusted for the
 # overall progress through the model
 feedback = QgsProcessingMultiStepFeedback(20, model_feedback)
 results = {}
 outputs = {}
 # Heights calculator
 alg_params = {
 'CELLSIZE': None,
 'CRS': None,
 'EXPRESSION': '\"DSM@1\" - \"DTM@1\"',
 'EXTENT': None,
 'LAYERS': parameters['dtm'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['HeightsCalculator'] = processing.run('qgis:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(1)
 if feedback.isCanceled():
 return {}
 # NDVI calculator
 alg_params = {
 'CELLSIZE': 0,
 'CRS': None,
 'EXPRESSION': 'sqrt(256* \"Zone@2\"- 256 * \"Zone@3\")',
 'EXTENT': None,
 'LAYERS': parameters['dtm'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['NdviCalculator'] = processing.run('qgis:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(2)
 if feedback.isCanceled():
 return {}
 # NDVI Selector
 alg_params = {
 'CELLSIZE': 0,
 'CRS': None,
 'EXPRESSION': '\"\'Output\' from algorithm \'NDVI calculator\'@1\"> 100',
 'EXTENT': None,
 'LAYERS': outputs['NdviCalculator']['OUTPUT'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['NdviSelector'] = processing.run('qgis:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(3)
 if feedback.isCanceled():
 return {}
 # Only NDVI
 alg_params = {
 'CELLSIZE': 0,
 'CRS': None,
 'EXPRESSION': '(\"\'Output\' from algorithm \'NDVI Selector\'@1\" =1)*\"\'Output\' from algorithm \'NDVI Selector\'@1\"',
 'EXTENT': None,
 'LAYERS': outputs['NdviSelector']['OUTPUT'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['OnlyNdvi'] = processing.run('qgis:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(4)
 if feedback.isCanceled():
 return {}
 # Build virtual raster
 alg_params = {
 'ADD_ALPHA': False,
 'ASSIGN_CRS': None,
 'INPUT': outputs['OnlyNdvi']['OUTPUT'],
 'PROJ_DIFFERENCE': False,
 'RESAMPLING': 0,
 'RESOLUTION': 1,
 'SEPARATE': False,
 'SRC_NODATA': '0',
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['BuildVirtualRaster'] = processing.run('gdal:buildvirtualraster', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(5)
 if feedback.isCanceled():
 return {}
 # True NDVI
 alg_params = {
 'CELLSIZE': 0,
 'CRS': None,
 'EXPRESSION': '(\"Zone@4\" -\"Zone@1\" ) /(\"Zone@4\" +\"Zone@1\" )',
 'EXTENT': None,
 'LAYERS': parameters['zone'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['TrueNdvi'] = processing.run('qgis:rastercalculator', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(6)
 if feedback.isCanceled():
 return {}
 # Polygonize (raster to vector)
 alg_params = {
 'BAND': 1,
 'EIGHT_CONNECTEDNESS': False,
 'FIELD': 'Value',
 'INPUT': outputs['BuildVirtualRaster']['OUTPUT'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['PolygonizeRasterToVector'] = processing.run('gdal:polygonize', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(7)
 if feedback.isCanceled():
 return {}
 # Extract by attribute
 alg_params = {
 'FIELD': 'Value',
 'INPUT': outputs['PolygonizeRasterToVector']['OUTPUT'],
 'OPERATOR': 0,
 'VALUE': '1',
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['ExtractByAttribute'] = processing.run('native:extractbyattribute', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(8)
 if feedback.isCanceled():
 return {}
 # Fix geometries
 alg_params = {
 'INPUT': outputs['ExtractByAttribute']['OUTPUT'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['FixGeometries'] = processing.run('native:fixgeometries', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(9)
 if feedback.isCanceled():
 return {}
 # JUSTNDVI
 alg_params = {
 'ALPHA_BAND': False,
 'CROP_TO_CUTLINE': True,
 'DATA_TYPE': 0,
 'INPUT': outputs['TrueNdvi']['OUTPUT'],
 'KEEP_RESOLUTION': False,
 'MASK': outputs['FixGeometries']['OUTPUT'],
 'MULTITHREADING': False,
 'NODATA': None,
 'OPTIONS': '',
 'SET_RESOLUTION': False,
 'SOURCE_CRS': None,
 'TARGET_CRS': None,
 'X_RESOLUTION': None,
 'Y_RESOLUTION': None,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Justndvi'] = processing.run('gdal:cliprasterbymasklayer', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(10)
 if feedback.isCanceled():
 return {}
 # NDVIValues
 alg_params = {
 'FIELD_NAME': 'NDVI',
 'INPUT_RASTER': outputs['Justndvi']['OUTPUT'],
 'RASTER_BAND': 1,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Ndvivalues'] = processing.run('native:pixelstopoints', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(11)
 if feedback.isCanceled():
 return {}
 # Clip raster by mask layer
 alg_params = {
 'ALPHA_BAND': False,
 'CROP_TO_CUTLINE': True,
 'DATA_TYPE': 0,
 'INPUT': outputs['HeightsCalculator']['OUTPUT'],
 'KEEP_RESOLUTION': False,
 'MASK': outputs['FixGeometries']['OUTPUT'],
 'MULTITHREADING': False,
 'NODATA': None,
 'OPTIONS': '',
 'SET_RESOLUTION': False,
 'SOURCE_CRS': None,
 'TARGET_CRS': None,
 'X_RESOLUTION': None,
 'Y_RESOLUTION': None,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['ClipRasterByMaskLayer'] = processing.run('gdal:cliprasterbymasklayer', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(12)
 if feedback.isCanceled():
 return {}
 # Mean NDVI
 alg_params = {
 'DISCARD_NONMATCHING': False,
 'INPUT': outputs['FixGeometries']['OUTPUT'],
 'JOIN': outputs['Ndvivalues']['OUTPUT'],
 'JOIN_FIELDS': None,
 'PREDICATE': 1,
 'SUMMARIES': 6,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['MeanNdvi'] = processing.run('qgis:joinbylocationsummary', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(13)
 if feedback.isCanceled():
 return {}
 # Heights
 alg_params = {
 'FIELD_NAME': 'Height',
 'INPUT_RASTER': outputs['ClipRasterByMaskLayer']['OUTPUT'],
 'RASTER_BAND': 1,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Heights'] = processing.run('native:pixelstopoints', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(14)
 if feedback.isCanceled():
 return {}
 # Peaks
 alg_params = {
 'DISCARD_NONMATCHING': True,
 'INPUT': outputs['FixGeometries']['OUTPUT'],
 'JOIN': outputs['Heights']['OUTPUT'],
 'JOIN_FIELDS': None,
 'PREDICATE': 1,
 'SUMMARIES': 3,
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Peaks'] = processing.run('qgis:joinbylocationsummary', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(15)
 if feedback.isCanceled():
 return {}
 # PeaksnNDVI
 alg_params = {
 'DISCARD_NONMATCHING': True,
 'INPUT': outputs['Peaks']['OUTPUT'],
 'JOIN': outputs['MeanNdvi']['OUTPUT'],
 'JOIN_FIELDS': 'NDVI_mean',
 'METHOD': 1,
 'PREDICATE': 2,
 'PREFIX': '',
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['Peaksnndvi'] = processing.run('qgis:joinattributesbylocation', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(16)
 if feedback.isCanceled():
 return {}
 # Add geometry attributes
 alg_params = {
 'CALC_METHOD': 0,
 'INPUT': outputs['Peaksnndvi']['OUTPUT'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['AddGeometryAttributes'] = processing.run('qgis:exportaddgeometrycolumns', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(17)
 if feedback.isCanceled():
 return {}
 # Extract by expression
 alg_params = {
 'EXPRESSION': 'NDVI_mean > 0.2 AND NDVI_mean IS NOT NULL AND Height_max > 1 AND Height_max IS NOT NULL AND area > 1',
 'INPUT': outputs['AddGeometryAttributes']['OUTPUT'],
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['ExtractByExpression'] = processing.run('native:extractbyexpression', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(18)
 if feedback.isCanceled():
 return {}
 # Join attributes by field value
 alg_params = {
 'DISCARD_NONMATCHING': True,
 'FIELD': 'Height',
 'FIELDS_TO_COPY': None,
 'FIELD_2': 'Height_max',
 'INPUT': outputs['Heights']['OUTPUT'],
 'INPUT_2': outputs['ExtractByExpression']['OUTPUT'],
 'METHOD': 1,
 'PREFIX': '',
 'OUTPUT': QgsProcessing.TEMPORARY_OUTPUT
 }
 outputs['JoinAttributesByFieldValue'] = processing.run('native:joinattributestable', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 feedback.setCurrentStep(19)
 if feedback.isCanceled():
 return {}
 # Delete duplicates by attribute
 alg_params = {
 'FIELDS': 'NDVI_mean',
 'INPUT': outputs['JoinAttributesByFieldValue']['OUTPUT'],
 'OUTPUT': parameters['Finaltrees']
 }
 outputs['DeleteDuplicatesByAttribute'] = processing.run('native:removeduplicatesbyattribute', alg_params, context=context, feedback=feedback, is_child_algorithm=True)
 results['Finaltrees'] = outputs['DeleteDuplicatesByAttribute']['OUTPUT']
 return results
 def name(self):
 return 'trees'
 def displayName(self):
 return 'trees'
 def group(self):
 return ''
 def groupId(self):
 return ''
 def createInstance(self):
 return Trees()

Is this possible?

Taras
35.7k5 gold badges77 silver badges151 bronze badges
asked Aug 31, 2019 at 0:23

2 Answers 2

1

With QGIS 3.4 and Windows 10 I have these deprecation warnings when running my standalone application :

C:\Program Files\QGIS 3.4\apps\qgis-ltr\python\qgis\utils.py:685: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
 mod = _builtin_import(name, globals, locals, fromlist, level)
C:\Program Files\QGIS 3.4\apps\qgis-ltr\python\plugins\db_manager\db_plugins\postgis\plugin.py:350: DeprecationWarning: invalid escape sequence \:
 uri = u"raster:gdal:%s:%s" % (self.name, re.sub(":", "\:", self.gdalUri()))
C:\PROGRA~1\QGIS3~1.4\apps\Python37\lib\site-packages\PyQt5\uic\objcreator.py:152: DeprecationWarning: 'U' mode is deprecated
 plugin = open(filename, 'rU')

And everything works fine.

I guess we can rely on QGis and Pyqt teams to keep their libs up to date before the warnings become errors.

answered Sep 2, 2019 at 8:35
4
  • my script worked for u? Commented Sep 3, 2019 at 19:29
  • @AN10 your script worked for me exactly like you: no error, just deprecation warnings (different warnings than the ones I have though). There is no output because the script does not have a main routine. Commented Sep 4, 2019 at 6:21
  • so should i just add a main that returns the output ? Commented Sep 4, 2019 at 21:29
  • @AN10 yes I guess Commented Sep 6, 2019 at 6:16
0

Your script has the definition of the processing algorithm class but in order for it to do something you need to instantiate the Trees class and use it.

Add this at the end of the file and then run it:

trees = Trees()
feedback = QgsProcessingFeedback()
context = QgsProcessingContext()
parameters = {} #add your parameters here
trees.initAlgorithm()
trees.processAlgorithm(parameters, context, feedback)
answered Oct 13, 2020 at 6:55

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.