Friday 21 July 2017

iterator - Simplify repetitive tasks in QGIS Graphical Modeler


enter image description here


Are there iterators that can be used in QGIS graphical modeler to simplify the model shown above. If not, is there any better way of simplifying the model?


The first column represents my input layers, second column is the intersection, third column is the output from the "intersection" operation, fourth column is the "join attribute by location" operation and fifth column is the result of the join operation.


I would like to carry out "intersection" and "join attribute by location" operations for a watershed analysis. The aim is compute Linear Morphometric parameters such as the total and mean length of streams of different orders, stream ratios and bifurcation ratio.



The first step is to intersect "order1 streams" with the watershed, and then intersect the "Order2 streams" with the same watershed. If there is an "order3 stream" shapefile provided then the intersection for this new layer should be performed. Therefore only "order1 streams" and "order2 streams" are mandatory, the rest depend on the provided watershed layer. For example if the watershed is an order 4 watershed then the streams required are upto "order4 streams".


Once the intersection is completed for all the available input layers, they are then joined by location to the watershed with the options to get the sum and mean of the intersected streams.


The image shows the correct procedure. If I do the operation outside of the modeler the results are correct. When I run the model I get this error.


"Error executing algorithm Order5_plus_wshed 'NoneType' object has no attribute 'dataProvider'".


This occurs if I have not provided an input for one of the optional parameters (i.e. the inputs e.g "order4 streams") However if I provide all inputs I get the results I need.


So, I would like to ask if there is a better way of setting up this task.



Answer



The way I would set your task up would be to create a custom script which provides greater flexibility than the modeler but can still provide a similar interface to its users. You can create one from:


Processing Toolbox > Scripts > Tools > Create new script


Then copy/paste the script below and save it into C:/Users/You/.qgis2/processing/scripts.



The script below tries to emulate what your model does. The script is not a final solution (especially since the paramaters I used for the Intersection and Join attribute by location tools may differ from what you defined) but hopefully you could use it as a template to expand and improve upon the script to suit your needs. To run it, simply select it from the Processing Toolbox after it has been saved.


I think the script does what you asked:




  • First two orders are mandatory so will be processed.




  • IF statements are used to ensure that any succeeding orders will only get processed if the correct one precedes it (e.g. order4 will only run if order3 has been selected).





  • In addition, messages are printed in the Python Console showing which orders are being processed.






##Example model=name
##Order1=vector
##Order2=vector
##Order3=optional vector
##Order4=optional vector
##Order5=optional vector

##Watershed=vector
##Order2_Wshed=output vector
##Order3_Wshed=output vector
##Order4_Wshed=output vector
##Order5_Wshed=output vector

order1 = processing.getObject(Order1)
order2 = processing.getObject(Order2)
order3 = processing.getObject(Order3)
order4 = processing.getObject(Order4)

order5 = processing.getObject(Order5)
watershed = processing.getObject(Watershed)

if Order3 is None:
print 'Processing Order1 and Order2'
else:
print 'Processing Order1, Order2 and Order3'
if Order4 is not None:
print 'Processing Order1, Order2, Order3 and Order4'
if Order5 is not None:

print 'Processing Order1, Order2, Order3, Order4 and Order5'

output_1a = processing.runalg("qgis:intersection", order1, watershed, None)
output_1b = processing.runalg("qgis:joinattributesbylocation", output_1a['OUTPUT'], watershed, u'intersects', 0, 0, '', 0, None)
output_2a = processing.runalg("qgis:intersection", order2, watershed, None)
output_2b = processing.runalg("qgis:joinattributesbylocation", output_2a['OUTPUT'], output_1b['OUTPUT'], u'intersects', 0, 0, '', 0, Order2_Wshed)

if Order3 is None:
pass
else:

output_3a = processing.runalg("qgis:intersection", order3, watershed, None)
output_3b = processing.runalg("qgis:joinattributesbylocation", output_3a['OUTPUT'], output_2b['OUTPUT'], u'intersects', 0, 0, '', 0, Order3_Wshed)
if Order4 is None:
pass
else:
output_4a = processing.runalg("qgis:intersection", order4, watershed, None)
output_4b = processing.runalg("qgis:joinattributesbylocation", output_4a['OUTPUT'], output_3b['OUTPUT'], u'intersects', 0, 0, '', 0, Order4_Wshed)
if Order5 is None:
pass
else:

output_5a = processing.runalg("qgis:intersection", order5, watershed, None)
output_5b = processing.runalg("qgis:joinattributesbylocation", output_5a['OUTPUT'], output_4b['OUTPUT'], u'intersects', 0, 1, 'sum, mean', 0, Order5_Wshed)

Below is a screenshot of the interface when running the script (which should look similar to when you run your model):


Running script


Few things to note:




  • Red box contain mandatory parameters





  • Green box contains optional parameters




  • Blue box contains mandatory parameter




  • Black box contains optional parameters to output results. The script will only output layers if the associated order is selected (e.g. if the input for order5 is not selected but the output for it is, an error will occur). Therefore, the user must select the inputs and the relevant outputs. This wasn't intentional but personally I think it's a good way to force the user to check the parameters carefully.







I used QGIS 2.12.3 (with Processing plugin version 2.12.2).


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...