3

I'm creating a new memory vector layer (polygon) copying data from a selected input layer on my plugin (QGIS version 2.18.2 on mac). New data columns (attributes) must be added with results of calculations. (Pseudocode)

    sourceLayer = self.layers[self.confirmedLayerIndex]  #layer used as input
    sourceFeats = [feat for feat in sourceLayer.getFeatures()]
    sourceGeometryType = ['Point','Line','Polygon'][sourceLayer.geometryType()]
    sourceCRS = sourceLayer.crs().authid()

    name = "layername"
    data = matrix with shape (d, d)
    labels = list with measures names

    newLayer = QgsVectorLayer(sourceGeometryType+'?crs='+sourceCRS, name, "memory")
    provider = newLayer.dataProvider()
    attr = sourceLayer.dataProvider().fields().toList()
    attr.extend([QgsField(label, QVariant.Double) for label in labels])
    provider.addAttributes(attr)
    newLayer.updateFields()
    provider.addFeatures(sourceFeats)

After creating the new fields with attr.extend and updating the layer, the dataProvider() method with changeAttributeValues() function is used to populate them with results:

for idxfeat, feat in enumerate(newLayer.getFeatures()):
    featid = int(feat.id())
    for idxlabel, label in enumerate(labels):
        idxfield = int(provider.fieldNameMap()[label])
        val = float(data[idxfeat, idxlabel])
        provider.changeAttributeValues({featid : {idxfield : val}})

QgsMapLayerRegistry.instance().addMapLayer(newLayer)

I'm pretty sure the input passed to changeAttributeValues is correct and the problem is related to the new fields setting. Looks like the dataProvider() can't locate the new fields. I tested on QGIS console fixing the column by one "original" field and it was updated, but trying to use the new created field results in NULL. It doesn't show any error but I could find log messages with what seems to be QGIS DB operations:

Attribute index 17 out of bounds [0;17]
Attribute index 18 out of bounds [0;17]
... 

I tested several different methods with layer.startEditing()/commitChanges() but nothing works and people mess up layer edit with dataprovider, this doesn't seems to be a good idea as point here https://gis.stackexchange.com/a/147399/92864. I also checked previous questions like Got Null values when updating attributes with PyQgis and Cannot get changeAttributeValues() to work in a loop but none of them are using memory layer or a copy.

Can someone help me understand what is happening?

Update:

I hardcoded the labels = list with measures names with names copied from the source layer instead of using the new fields and the function updated the columns successfully, confirming that the problem is with the new fields setting. Do I need to set a geometry to the new fields? Adding a field is not just extending a current feature?

1

Found the solution making more tests! Just needed to invert the order of the block:

provider.addAttributes(attr)
newLayer.updateFields()
provider.addFeatures(sourceFeats)

to:

provider.addFeatures(sourceFeats)
provider.addAttributes(attr)
newLayer.updateFields()

Something that make sense as I'm trying to update the attribute but the features were being added only on the next step, changing the order made it work perfectly and faster that layer edit method.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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