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?

1
  • 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). Commented Aug 3, 2020 at 11:39

1 Answer 1

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.

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.