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
  • 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 – Germán Carrillo Nov 7 '16 at 20:33
  • @GermánCarrillo It does not work when I remove the "updatefeature" line... – m.siret Nov 7 '16 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. – Germán Carrillo Nov 7 '16 at 21:55
  • @GermánCarrillo I tested it, and it takes longer compare to "updateFeature" way... – m.siret Nov 7 '16 at 22:55
  • 1
    Post your full code. Broken out like that is hard to read. – Nathan W Nov 8 '16 at 10:30
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, privacy policy and cookie policy

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