6

I have two input vector layers (one point and one line layer). I loop through every feature in the input-line-layer and calculate some things (with the help of the point layer).

What I am trying to do now is to generate an output line layer for which I want to have the following six fields:

1. QgsField('id', QVariant.String)
2. QgsField('vto', QVariant.Double)
3. QgsField('vfrom', QVariant.Double)
4. QgsField('priority', QVariant.Int)
5. QgsField('node1', QVariant.String)
6. QgsField('node2', QVariant.String)

Based on those defined fields, I want to add some features to the output layer, but I do not know how to define the fields (of the output layer) and how to add features to the output layer in QGIS3.

Note: I am using the processing algorithm template for QGIS3 from Underdark: see https://anitagraser.com/2018/03/25/processing-script-template-for-qgis3/

Based on her template, she writes this:

    def processAlgorithm(self, parameters, context, feedback):
        inEdges = self.parameterAsSource(parameters, 
                       self.INPUT_VECTOR_LAYER_EDGES, context)
        inNodes = self.parameterAsSource(parameters, 
                       self.INPUT_VECTOR_LAYER_NODES, context)
        (sink, dest_id) = self.parameterAsSink(parameters, 
                       self.OUTPUT_VECTOR_LAYER_MERGED, context,
                       inEdges.fields(), inEdges.wkbType(), inEdges.sourceCrs())

In the line which starts with (sink, dest_id), underdark has declared an outputlayer that takes the same fields as the inputlayer. But how can I declare an outputlayer with my customized fields (which are not ident with the fields from the inputlayer)?

EDIT: As suggested from root676, I altered my code a little bit:

# 1. First of all, I defined a variable which holds the definition of my fields
outFields = QgsFields()

# 2. Then, I defined the fields
outFields.append(QgsField('id', QVariant.String))
outFields.append(QgsField('vto', QVariant.Double))
outFields.append(QgsField('vfrom', QVariant.Double))
outFields.append(QgsField('priority', QVariant.Int))
outFields.append(QgsField('node1', QVariant.String))
outFields.append(QgsField('node2', QVariant.String))

# 3. Then I created the output sink with the previously defined fields
(sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_VECTOR_LAYER_MERGED, context,
                                           outFields, inEdges.wkbType(), inEdges.sourceCrs())

# 4. I created a new feature that will be added to the outputlayer after I set its attribute values.
newEdge = QgsFeature()

# 5. The ERROR happens when I try to set an attribute value like this:
newEdge['id'] = edgeIdTrimmed

The error I am getting is as followed:

Traceback (most recent call last): File "", line 143, in processAlgorithm KeyError: 'id'

EDIT: I solved the problem by initializing the new QgsFeature with my defined Fields variable. See below:

newEdge = QgsFeature(outFields)
3
  • 1
    Did my answer help you with you with your problem?
    – root676
    Commented Dec 4, 2018 at 19:41
  • I have tried your suggestion, but still encounter an error. Please have a look to my edited question above! Thank you so much!
    – applebrown
    Commented Dec 7, 2018 at 7:59
  • 1
    Good to see that it works now! I think you forgot do set the features fields (´feat.setFields(your_fields)´) but initializing the fields with the feature seems to work fine as well.
    – root676
    Commented Dec 7, 2018 at 10:31

1 Answer 1

10
+50

Here is an example of a possible base-layout of your processAlgorithm() method (just a quick wrap-up of the basic field related code you were asking about - has to be embedded into your context):

def processAlgorithm(self, parameters, context, feedback):
    #get your input layers
    inEdges = self.parameterAsSource(parameters, 
                   self.INPUT_VECTOR_LAYER_EDGES, context)
    inNodes = self.parameterAsSource(parameters, 
                   self.INPUT_VECTOR_LAYER_NODES, context)

    #define your fields
    your_fields = QgsFields()

    #append fields
    your_fields.append(QgsField('id', QVariant.String))
    your_fields.append(QgsField('vto', QVariant.Double))
    your_fields.append(QgsField('vfrom', QVariant.Double))
    your_fields.append(QgsField('priority', QVariant.Int))
    your_fields.append(QgsField('node1', QVariant.String))
    your_fields.append(QgsField('node2', QVariant.String))

    #create the output sink
    (sink, dest_id) = self.parameterAsSink(parameters, self.OUTPUT_VECTOR_LAYER_MERGED, context, your_fields, inEdges.wkbType(), inEdges.sourceCrs())

    #do some calculations with inEdges and inNodes

    #somewhere in your while/for loops create a new feature object
    feat = QgsFeature()

    #set your fields of the feature
    feat.setFields(your_fields)

    #set the attribute values like this 
    feat['vto'] = #some_vto_value

    #set geometry of feature
    feat.setGeometry(geom)

    #add feature to sink
    sink.addFeature(feat, QgsFeatureSink.FastInsert)        

    #return feature sink
    results = {}
    results[self.OUTPUT_VECTOR_LAYER_MERGED] = dest_id
    return results

The following steps are necessary to output a sink with custom fields (see corresponding code comments):

  1. get your input layers
  2. define your fields as QgsFields object
  3. append the corresponding QgsField objects to the QgsFields
  4. create the output QgsFeatureSink using the fields from the variable your_fields
  5. do your calculations with the inEdges and inNodes layers
  6. create features using your_fields, set their attributes and geometry in the calculation process
  7. add the features to the sink
  8. return the sink as new output layer.
1
  • hey @root676 ! I have tried your solution but I still get some error when trying to set an attribute value of the feature (it says KeyError: 'id' when writing newFeature['id'] = edgeid. I have edited my question so please have a look!
    – applebrown
    Commented Dec 7, 2018 at 7:49

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.