1

I am working on a QGIS plugin for which I am iterating over an inputlayer (point) and requesting a responselayer (polygon) for each inputfeature. The responselayer then contains several responsefeatures for each inputfeature.

I am trying to create a new vector layer having the geometry of each responsefeature and its attributes. Also the inputfeatures attributes shall be copied over.

So far I have managed to create the new vector layer and adding the inputfeatures x times to it. But I am struggling to set the geometry and attributes of it to the responselayer's ones.

This is my relevant code:

# creating outputlayer
Isochrones_Memorylayer_VL = QgsVectorLayer("Polygon?crs=epsg:4326", "Isochrones", "memory") # Create temporary polygon layer (output file)
Isochrones_Memorylayer_PR = Isochrones_Memorylayer_VL.dataProvider()
Isochrones_Memorylayer_VL.startEditing()
Isochrones_Memorylayer_PR.addAttributes(isochrones_selectedLayer.fields()) # Copy all fieldnames of inputlayer to outputlayer  
Isochrones_Memorylayer_PR.addAttributes([QgsField("Isochrone_UID", QVariant.Int),QgsField("Isochrone_Error", QVariant.String),QgsField("Isochrone_URL", QVariant.String),QgsField("Isochrone_Time",QVariant.Int)]) # Add Error and URL Field to outputlayer
Inputlayer_outFeat = QgsFeature() # set QgsFeature

iterating through input layer

for Inputlayer_Feature in Inputlayer_Features: # doing stuff # e.g. requesting response layer having several features for each feature of input layer

# iterating through response layer
for feat in Isochrone_Feature:
            Isochrones_Memorylayer_PR.addFeatures([Inputlayer_outFeat]) # Add attributes of inputlayer to outputlayer
            #Isochrones_Memorylayer_PR.addFeature(feat)
            #Isochrones_Memorylayer_PR.changeAttributeValues(feat.id(), 2, 30)
            #Isochrones_Memorylayer_PR['Isochrone_URL'] = str(isochrone_url)
            #Isochrones_Memorylayer_PR.changeFeatures(feat.geometry())

As you can see the second loop is a mess of a few things I have tried. I think the way to go should be changeAttributeValues and changeGeometryValues, but from the docs I have no idea how to actually use it. An example would help here. I already took a look at the cookbook. The only question with an example I can find is six years old and doesn't help solving my question. When trying the answer, I am getting TypeError: QgsVectorDataProvider.changeAttributeValues(): argument 1 has unexpected type 'int'. Maybe due to changes in the API? But since I am still a beginner in pyqgis it could also be some simple stuff.

How can I set the geometry of my new vector layer to the responselayers geometry and add the responselayers attributes (only "time", the other attributes like url, error, etc. are generic) to it?

Vince
  • 20,017
  • 15
  • 45
  • 64
MrXsquared
  • 34,292
  • 21
  • 67
  • 117
  • 1
    You want to change the feature after addFeature. Do it before on feat like feat.setGeometry(your_geom) and feat.setAttribute("Isochrone_UID", my_uid_value), and after, lyr.addFeature(feat). – J. Monticolo Aug 03 '20 at 11:39

1 Answers1

0

I solved it the following. I can not say whether this is smart or not, but it is working:

isochrone_uid_counter = 0
isochrone_id_counter = 0

Create the Vectorlayer

Isochrones_Memorylayer_VL = QgsVectorLayer("MultiPolygon?crs=epsg:4326", "Isochrones", "memory") # Create temporary polygon layer (output file) Isochrones_Memorylayer_PR = Isochrones_Memorylayer_VL.dataProvider() Isochrones_Memorylayer_VL.startEditing() # Enter editing mode Isochrones_Memorylayer_PR.addAttributes([QgsField("Isochrone_Time",QVariant.Int),QgsField("Isochrone_UID", QVariant.Int),QgsField("Isochrone_ID", QVariant.Int),QgsField("Isochrone_Error", QVariant.String),QgsField("Isochrone_URL", QVariant.String)]) # Add Error and URL Field to outputlayer
Isochrones_Memorylayer_PR.addAttributes(isochrones_selectedLayer.fields()) # Copy all fieldnames of inputlayer to outputlayer
Inputlayer_NumberOfFields = isochrones_selectedLayer.fields().count() # count number of fields in inputlayer Inputlayer_outFeat = QgsFeature() # set QgsFeature

iterating through input layer

for Inputlayer_Feature in Inputlayer_Features: # doing stuff # e.g. requesting response layer having several features for each feature of input layer Inputlayer_Attributes = Inputlayer_Feature.attributes() # fetch attributes
Inputlayer_outFeat.setAttributes(Inputlayer_Feature.attributes()) # set the attributes

#iterate trough isochrone
isochrone_id_counter = isochrone_id_counter + 1
for Isochrone_Feature in Isochrone_Features:
    isochrone_uid_counter = isochrone_uid_counter + 1
    Isochrones_Memorylayer_PR.addFeature(Isochrone_Feature) # copy features of responselayer including geometry and attributes (it is always only one attribute) to new layer
    attrs_isochrone = { 1 : isochrone_uid_counter, 2 : isochrone_id_counter, 3 : Isochrones_Error , 4 : url } # set further generic attributes
    Isochrones_Memorylayer_PR.changeAttributeValues({ Isochrone_Feature.id() : attrs_isochrone }) # change attribute values of new layer to the just set ones
    for i in range(0, Inputlayer_NumberOfFields): # iterate over new layer as many fields as the input layer has
        attrs_inputlayer = { i + 5 : Inputlayer_Attributes[i] } # set attributes of inputlayer (+5 because we added 5 new fields before)
        Isochrones_Memorylayer_PR.changeAttributeValues({ Isochrone_Feature.id() : attrs_inputlayer }) # change attribute values of new layer to the ones from inputlayer 
    Isochrones_Memorylayer_VL.updateFields() # make sure to fetch changes from the provider

Isochrones_Memorylayer_VL.commitChanges() # Commit changes QgsProject.instance().addMapLayer(Isochrones_Memorylayer_VL)# Show in project

My first mistake was to copy the features (including geometry) of my inputlayer instead of the response layer. So I just copy these features which always have one attribute. Then add my generic attributes which are always 4. At last I am iterating over the fields of my inputlayer and add these attributes.

MrXsquared
  • 34,292
  • 21
  • 67
  • 117