2

Can someone help me understand how to properly parameterize the 'Select by Location' geoprocessing tool when implementing it in a QGIS processing plugin. I have been following the tutorial on building a processing plugin, however I get an 'Unable to execute algorithm' error when I try to run my processing plugin. At thi point, I just want to be able to parameterize and run a the basic geoprocessing tool 'Select by Location' before I start changing things.....

Here is a snippet of code from the two functions used to define the parameters, and implement the processAlgorithm.

As written, I receive the error: Unable to execute algorithm Incorrect parameter value for INPUT

I have compared the output in the log window for the 'Select by Location' tool in Vector-->Research--> Select by location, which looks like this:

Input parameters:
{ 'INPUT' : "crs='EPSG:4326' url='https://services3.arcgis.com/T4QMspbfLg3qTGWY/ArcGIS/rest/services/Fire_History_Perimeters_Public/FeatureServer/0'", 
  'INTERSECT' : '/media/williamkessler/extradrive1/BearToothGroup/Data/Airports_and_drivetime/Airports.gpkg|layername=1hr_Isochrone', 
  'METHOD' : 0, 
  'PREDICATE' : [0] }
  
  Execution completed in 0.44 seconds
  Results:
  {'OUTPUT': 'FH_Perimeter_f0404e04_0298_4fb3_bd78_5534a7d1fe4f'}

and what comes from my tool:

Input parameters:
  { 'INPUT' : "arcgisfeatureserver://crs='EPSG:4326' url='https://services3.arcgis.com/T4QMspbfLg3qTGWY/ArcGIS/rest/services/Fire_History_Perimeters_Public/FeatureServer/0'", 
  'Intersecting Layer' : '/media/williamkessler/extradrive1/BearToothGroup/Data/Airports_and_drivetime/Airports.gpkg|layername=1hr_Isochrone', 
  'METHOD': 0,
  'Predicate' : [0] }'

  Unable to execute algorithm
  Incorrect parameter value for INPUT
  Execution failed after 0.05 seconds

The only difference I can see, is a difference in how the CRS is specified? How do I change this? Will it solve my issue?

def initAlgorithm(self, config):
    """
    Here we define the inputs and output of the algorithm, along
    with some other properties.
    """
    # I add the input vector features source. It can have any kind of geometry.
    self.addParameter(
        QgsProcessingParameterFeatureSource(
            self.INPUT,
            self.tr('Input layer'),
            [QgsProcessing.TypeVectorAnyGeometry]
        )
    )

    # I add the vector features source to compare the input against. It can have any kind of geometry.
    self.addParameter(
        QgsProcessingParameterFeatureSource(
            self.INTERSECT,
            self.tr('INTERSECTING layer'),
            [QgsProcessing.TypeVectorAnyGeometry]
        )
    )

    # I specify the geometric predicate to base the selection on. It  is an enum parameter with multiselect (the same as in the basic 'select by location tool' 
    self.addParameter(
        QgsProcessingParameterEnum(
            name = self.PRED, 
            description = self.tr('Geometric Predicate'), 
            options = ["Intersect","Contain","Disjoint","Equal","Touch","Overlap","Are Within", "Cross"],
            defaultValue = "Intersect",
            allowMultiple = True,
        )
    )
    
    # We add a feature sink in which to store our processed features (this
    # usually takes the form of a newly created vector layer when the
    # algorithm is run in QGIS).
    self.addParameter(
        QgsProcessingParameterFeatureSink(
            self.OUTPUT,
            self.tr('Output layer')
        )
    )

def processAlgorithm(self, parameters, context, feedback):
    """
    Here is where the processing itself takes place.
    """

    # Retrieve the feature source and sink. The 'dest_id' variable is used
    # to uniquely identify the feature sink, and must be included in the
    # dictionary returned by the processAlgorithm function.
    source = self.parameterAsSource(parameters, self.INPUT, context)

    (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT,
            context, source.fields(), source.wkbType(), source.sourceCrs())

    intersect = self.parameterAsSource(parameters, self.INTERSECT, context)

    predicate = self.parameterAsSource(parameters, self.PRED, context)

    # method = self.parameterAsSource(parameters, self.METHOD, context)

    # Compute the number of steps to display within the progress bar and
    # get features from source
    total = 100.0 / source.featureCount() if source.featureCount() else 0
    features = source.getFeatures()
    
    ## Here is where I attempt to implement the 'select by location' processing tool: 
    processing.run("qgis:selectbylocation", {'INPUT':source, 'PREDICATE': predicate, 'INTERSECT': intersect, 'METHOD':0})

 '''
    # for current, feature in enumerate(features):
    #     # Stop the algorithm if cancel button has been clicked
    #     if feedback.isCanceled():
    #         break

    #     # Add a feature in the sink
    #     # sink.addFeature(feature, QgsFeatureSink.FastInsert)

    #     # processing.run("qgis:selectbylocation", {'INPUT':feature, 'PREDICATE': predicate, 'INTERSECT': intersect, 'METHOD':0})
    #     # Update the progress bar
    #     feedback.setProgress(int(current * total))

    # Return the results of the algorithm. In this case our only result is
    # the feature sink which contains the processed features, but some
    # algorithms may return multiple feature sinks, calculated numeric
    # statistics, etc. These should all be included in the returned
    # dictionary, with keys matching the feature corresponding parameter
    # or output names.
    return {self.OUTPUT: dest_id}

1 Answer 1

1

I figured out the answer to my own question. It's a two parter- I had the inputs misspecified- the processessing tool I was trying to call requires vectorLayers as input, not 'FeatureSource'

   self.addParameter(
    QgsProcessingParameterFeatureSource(
        self.INPUT,
        self.tr('Input layer'),
        [QgsProcessing.TypeVectorAnyGeometry]
    )
)

becomes:

  self.addParameter(
    QgsProcessingParameterVectorLayer(
        self.INPUT,
        self.tr('Input layer'),
        [QgsProcessing.TypeVectorAnyGeometry]
    )
)

and,

When calling your parameters in the processAlgorithm function, the class called needs to match the parameter type. For instance:

source = self.parameterAsSource(parameters, self.INPUT, context)

predicate = self.parameterAsSource(parameters, self.PRED, context)

should be:

source = self.parameterAsVectorLayer(parameters, self.INPUT, context)

predicate = self.parameterAsEnum(parameters, self.PRED, context)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.