Tuesday, 5 June 2018

pyqgis - Defining fields and adding features to output layer using QGIS?


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 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 which 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. The 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 which 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 initialising the new QgsFeature with my defined Fields variable. See below:



newEdge = QgsFeature(outFields)

Answer



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.


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