Thursday, 17 March 2016

qgis 3 - No output in PyQGIS standalone script running Distance Matrix?


I am trying to create a standalone PyQGIS script which runs the Distance Matrix in QGIS 3, see below:



######### INITIALISE QGIS STANDALONE ################

import sys

from qgis.core import (
QgsApplication,
QgsProcessingFeedback,
QgsVectorLayer,
QgsField,
QgsFields,
QgsProperty,
QgsProcessingFeatureSourceDefinition,
QgsProcessingOutputLayerDefinition
)


#start QGIS instance without GUI
QgsApplication.setPrefixPath('/usr/share/qgis', True)
myqgs = QgsApplication([], False)
myqgs.initQgis()

######### INITIALISE THE PROCESSING FRAMEWORK ################

# Append the path where processing plugin can be found (assumes Debian)
sys.path.append('/usr/share/qgis/python/plugins')


#import modules needed
import processing
from processing.core.Processing import Processing

#start the processing module
processing.core.Processing.Processing.initialize()

######### Set Distance Matrix plugin parameters ############################


# I used this command in the QGIS3 python console
# >>> processing.algorithmHelp("qgis:distancematrix")
# to get the object types it accepts for each parameter

inputlayer = QgsVectorLayer('/path/to/myinputfile.shp', 'layer 1', 'ogr')
targetlayer = QgsVectorLayer('/path/to/mytargetfile.shp', 'layer 2', 'ogr')

inputfield = QgsProperty.fromField("InputPointID")
targetfield = QgsProperty.fromField("TargetPointID")


matrixtype = QgsProperty.fromValue(0)
nearestpoints = QgsProperty.fromValue(0)

outputlayer = QgsProcessingOutputLayerDefinition('/path/to/myoutputfile.csv')

params = {
'INPUT' : inputlayer,
'INPUT_FIELD' : inputfield,
'TARGET' : targetlayer,
'TARGET_FIELD' : targetfield,

'MATRIX_TYPE' : matrixtype,
'NEAREST_POINTS' : nearestpoints,
'OUTPUT' : outputlayer
}

feedback = QgsProcessingFeedback()

res = processing.run('qgis:distancematrix', params, feedback=feedback)
res['OUTPUT'] # Access your output layer



The script runs without errors but I don't get an output file. I have looked at the PYQGIS 3 API reference and searched more generally but there are so few worked examples for standalone PYQGIS3.


I have also run the command below in QGIS3 and used the field types it recommends but it still doesn't work:


processing.algorithmHelp("qgis:distancematrix") 

Any ideas what could be wrong with my script?


From Failed to create memory layers in QGIS application on Linux, I added the following code to check if the input layers were loading properly.


#Input Layers Validity Check
print(inputlayer.isvalid())
print(targetlayer.isvalid())


I got a False result on both layers.


Then using PyQGIS QgsVectorLayer() Loading Invalid Layer in Standalone Python Script? I found that the input layers were not loading because I had the wrong prefix. I replaced the below.


QgsApplication.setPrefixPath('/usr/share/qgis', True)

With this


QgsApplication.setPrefixPath('/usr', True)

It is now creating a blank csv file as the output (which is progress) but its still throwing an error when it runs, see below. Its a step forward from where it was but still not fixed yet.


Traceback (most recent call last):

File "/path/to/distmatrixqgis3standalonenogui.py", line 99, in
res = processing.run('qgis:distancematrix', params, feedback=feedback)
File "/usr/share/qgis/python/plugins/processing/tools/general.py", line 96, in run
return Processing.runAlgorithm(algOrName, parameters, onFinish, feedback, context)
File "/usr/share/qgis/python/plugins/processing/core/Processing.py", line 183, in runAlgorithm
raise QgsProcessingException(msg)
_core.QgsProcessingException: There were errors executing the algorithm.

Answer



I have found and fixed the final errors. I tried changing how each algorthim parameter got its value.


By changing the code below:




inputfield = QgsProperty.fromField("InputPointID")
targetfield = QgsProperty.fromField("TargetPointID")


To this:



inputfield = QgsProperty.fromValue("InputPointID")
targetfield = QgsProperty.fromValue("TargetPointID")



It has fixed the final problems and the script runs well.


My final working example of the PYQGIS 3 standalone code (Including all updates described above) to run the QGIS 3 Distance Matrix in the OS shell is as below. For info/interest, I will be tweaking it next to run in GNU Parallel; I can do that bit so I won't take up any more time on this question. Thanks to everyone. Question closed.




######### INITIALISE QGIS STANDALONE ################

import sys
from qgis.core import (
QgsApplication,

QgsProcessingFeedback,
QgsVectorLayer,
QgsField,
QgsFields,
QgsProperty,
QgsProcessingFeatureSourceDefinition,
QgsProcessingOutputLayerDefinition
)

#start QGIS instance without GUI

#Make sure the prefix is correct. Even though QGIS is in '/usr/share/qgis',
#the prefix needs to be '/usr' (assumes Debian OS)

QgsApplication.setPrefixPath('/usr', True)
myqgs = QgsApplication([], False)
myqgs.initQgis()

######### INITIALISE THE PROCESSING FRAMEWORK ################

# Append the path where processing plugin can be found (assumes Debian OS)

sys.path.append('/usr/share/qgis/python/plugins')

#import modules needed
import processing
from processing.core.Processing import Processing

#start the processing module
processing.core.Processing.Processing.initialize()

######### Set Distance Matrix plugin parameters ############################


# I used this command in the QGIS3 python console
# >>> processing.algorithmHelp("qgis:distancematrix")
# to get the object types it accepts for each parameter

inputlayer = QgsVectorLayer('/path/to/myinputfile.shp', 'layer 1', 'ogr')
targetlayer = QgsVectorLayer('/path/to/mytargetfile.shp', 'layer 2', 'ogr')

#do an Input Layers Validity Check
print(inputlayer.isvalid())

print(targetlayer.isvalid())

inputfield = QgsProperty.fromValue("InputPointID")
targetfield = QgsProperty.fromValue("TargetPointID")

matrixtype = QgsProperty.fromValue(0)
nearestpoints = QgsProperty.fromValue(0)

outputlayer = QgsProcessingOutputLayerDefinition('/path/to/myoutputfile.csv')


params = {
'INPUT' : inputlayer,
'INPUT_FIELD' : inputfield,
'TARGET' : targetlayer,
'TARGET_FIELD' : targetfield,
'MATRIX_TYPE' : matrixtype,
'NEAREST_POINTS' : nearestpoints,
'OUTPUT' : outputlayer
}


feedback = QgsProcessingFeedback()

res = processing.run('qgis:distancematrix', params, feedback=feedback)
res['OUTPUT'] # Access your output layer

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...