1

I am trying to modify attributes of features in QGIS comparing attributes with list'elements. First I define new attributes that need to be completed:

layer_intersected.dataProvider().addAttributes([QgsField("ID_acc",QVariant.Int,
    QgsField("Nb_acc", QVariant.Int)])
layer_intersected.updateFields()

Then, I iterate over my features:

layer_intersected.startEditing()
for feature in layer_intersected.getFeatures():

I have two lists containing elements. Now, I want to test if the first attribute ("NOMBRE") is in one of the extracts of "list1" (the list is divided into a certain number of elements, each part of elements is an 'extract' of list) and if the second attribute ("nombre_2") is also in the same extract of "list2":

for i in xrange(0, len(list1), len(list_streets_network)):
    l_streets_t1 = list1[i:i+len(list_streets_network)]
    set_l_streets_t1 = set(list1[i:i+len(list_streets_network)])
    set_l_streets_t2 = set(list2[i:i+len(list_streets_network)])
    l_id = list_id_acc[i:i+len(list_streets_network)]
    l_acc = list_nb_acc[i:i+len(list_streets_network)]
    if feature["NOMBRE"] in set_l_streets_t1 and feature["nombre_2"] in set_l_streets_t2:

Then, if it is the case, I complete the attributes created

         index1 = l_streets_t1.index(feature["NOMBRE"])
         feature["ID_acc"] = l_id[index1]
         feature["Nb_acc"] = l_acc[index1]
         layer_intersected.updateFeature(feature)

Finally:

layer_intersected.commitChanges() 
return layer_intersected

My problem is the speed of this code. I have to do this for thousands of features, and it takes days to calculate... I am sure there is a faster solution, but I do not know how to improve it...

I had a look on Numpy doc, but did not find the best solution... If someone has an idea, please help me ! :).

Here is the full code of the function:

> def create_id_for_right_matches(layer_intersected, list1, list2, list_id_acc, list_nb_acc, list_streets_network): 
    layer_intersected.dataProvider().addAttributes([QgsField("ID_acc", QVariant.Int), QgsField("Nb_acc", QVariant.Int)])
    layer_intersected.updateFields()
    layer_intersected.startEditing()
    request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes(['NOMBRE', 'nombre_2'], layer_intersected.fields())
        for feature in layer_intersected.getFeatures(request):
            for i in xrange(0, len(list1), len(list_streets_network)):
                l_streets_t1 = list1[i:i+len(list_streets_network)]
                set_l_streets_t1 = set(list1[i:i+len(list_streets_network)]) 
                set_l_streets_t2 = set(list2[i:i+len(list_streets_network)]) 
                l_id = list_id_acc[i:i+len(list_streets_network)]
                l_acc = list_nb_acc[i:i+len(list_streets_network)]
                if feature["NOMBRE"] in set_l_streets_t1 and feature["nombre_2"] in set_l_streets_t2:
                    index1 = l_streets_t1.index(feature["NOMBRE"])
                    feature["ID_acc"] = l_id[index1]
                    feature["Nb_acc"] = l_acc[index1]
                    layer_intersected.updateFeature(feature)
    layer_intersected.commitChanges()
    return layer_intersected
9
  • 1) Remove the layer_intersected.updateFeature(feature) line. You don't need it and it's inefficient. 2) Here you can find tips to optimize your getFeatures() call: nyalldawson.net/2016/10/speeding-up-your-pyqgis-scripts Commented Nov 7, 2016 at 20:33
  • @GermánCarrillo It does not work when I remove the "updatefeature" line...
    – m.siret
    Commented Nov 7, 2016 at 21:49
  • Try switching to this way of changing feature attributes layer.changeAttributeValue(fid, fieldIndex, newValue) (as indicated in the post I mentioned) instead of feature["ID_acc"] = l_id[index1] because, I repeat, updateFeature(feature) is inefficient. Commented Nov 7, 2016 at 21:55
  • @GermánCarrillo I tested it, and it takes longer compare to "updateFeature" way...
    – m.siret
    Commented Nov 7, 2016 at 22:55
  • 1
    Post your full code. Broken out like that is hard to read.
    – Nathan W
    Commented Nov 8, 2016 at 10:30

1 Answer 1

1

I improved my code by inversing "for" loops, that gains time, but not enough...

Now my code looks like :

    layer_intersected.dataProvider().addAttributes([QgsField("ID_acc", QVariant.Int), QgsField("Nb_acc", QVariant.Int)])
    layer_intersected.updateFields()
    layer_intersected.startEditing()
    request = QgsFeatureRequest().setFlags(QgsFeatureRequest.NoGeometry).setSubsetOfAttributes(['NOMBRE', 'nombre_2'], layer_intersected.fields())
    for i in xrange(0, len(list1), len(list_streets_network)):
        l_streets_t1 = list1[i:i+len(list_streets_network)]
        set_l_streets_t1 = set(list1[i:i+len(list_streets_network)])
        set_l_streets_t2 = set(list2[i:i+len(list_streets_network)])
        l_id = list_id_acc[i:i+len(list_streets_network)]
        l_acc = list_nb_acc[i:i+len(list_streets_network)]
        for feature in layer_intersected.getFeatures(request):
            if feature["NOMBRE"] in set_l_streets_t1 and feature["nombre_2"] in set_l_streets_t2:
                index1 = l_streets_t1.index(feature["NOMBRE"])
                feature["ID_acc"] = l_id[index1]
                feature["Nb_acc"] = l_acc[index1]
                layer_intersected.updateFeature(feature)

If someone has another idea, I would be pleased to hear from him...

Thanks

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.