1

I've been using PyQGIS for a few of weeks. I'd write a script which shows all earthshakes responding to given parameters, so I wrote this code:

from PyQt5.QtGui import *
from PyQt5.QtCore import QVariant
import processing
layerTerremoti = QgsVectorLayer("LayerGIS/totaleepicentriterremotiinunareadi200kmdatoscanaliguria.gpkg", "Terremoti", "ogr")
terrSelezionati = QgsVectorLayer("LayerGIS/terrSelezionati.shp")
with edit(terrSelezionati):
    for feat in terrSelezionati.getFeatures():
        terrSelezionati.deleteFeature(feat.id())

        
layer = qgis.utils.iface.activeLayer()
widgetGetBuff = iface.messageBar().createMessage("Buffer Layer", "Show Me")
widgetGetIntervalloInizio = iface.messageBar().createMessage("IntervalloInizio", "Show me")
widgetGetIntervalloFine = iface.messageBar().createMessage("IntervalloFine", "Show me")
elementi_selezionati = layer.selectedFeatures()

buffDist, ok = QInputDialog().getInt(widgetGetBuff, "Inserimento parametro buffer", "inserisci distanza buffer in Km", 0, 10, 200, QLineEdit.Normal)
if ok and buffDist:
    rangeInizio, ok = QInputDialog().getInt(widgetGetIntervalloInizio, "Inserimento 
    parametro intervallo", "Inserisci prima data del range temporale", 1000, 1000, 2010, 
    QLineEdit.Normal)
    rangeFine, ok = QInputDialog().getInt(widgetGetIntervalloFine, "Inserimento parametro 
    intervallo", "Inserisci seconda data del range temporale", 1001, 1100, 2020, 
    QLineEdit.Normal)
    aRispettoLayer = QgsVectorLayer('Polygon?crs=EPSG:3003', 'areaRispetto', 'memory')
    vpr = terrSelezionati.dataProvider()
    pr = aRispettoLayer.dataProvider()
    count = 0
    for i in elementi_selezionati:
        buff = i.geometry().buffer(buffDist*1000,18)
        b = QgsFeature()
        b.setGeometry(buff)
        pr.addFeatures([b])
    
    for ftre in layerTerremoti.getFeatures():

        if (ftre['Anno'] >= rangeInizio) and (ftre['Anno'] <= rangeFine):
            count = count +1
            QgsFeature(ftre)
            vpr.addFeatures([ftre])
        
    terrSelezionati.updateExtents()

    outres = processing.run("gdal:clipvectorbypolygon", {
        'INPUT': terrSelezionati,
        'MASK' : aRispettoLayer,
        'OUTPUT': 'LayerGIS/terremotiRitag.shp'
    })
    terremotiRitagliati = 
    QgsVectorLayer('LayerGIS/terremotiRitag.shp',"TerrRitagliati","ogr")
    tr = terremotiRitagliati.dataProvider()
    tr.addAttributes([QgsField("Anno", QVariant.Int)])
    terremotiRitagliati.updateFields()
    indCampo = terremotiRitagliati.fields().indexOf("Anno")
    
    conto = 0
    confronto = 0
    for f in terremotiRitagliati.getFeatures():
        
        conto = conto + 1
        
        tr.addFeatures([f])
        terremotiRitagliati.updateFeature(f)
    print("conto")
    print(conto)
    for el in layerTerremoti.getFeatures():
        confronto = el['N15']
            
        
        terremotiRitagliati.startEditing()
        for g in terremotiRitagliati.getFeatures():
            if confronto == g['id']:
                terremotiRitagliati.changeAttributeValue(g.id(), indCampo , el['Anno'])
                terremotiRitagliati.updateFeature(g)
                print(g["Anno"])
        terremotiRitagliati.commitChanges()
    countMsg = QMessageBox()
    
    if conto> 0:
        countMsg.setText("Sono stati trovati " + str(conto) + " terremoti tra il " +  
        str(rangeInizio) + "e il " + str(rangeFine))
    else:
        countMsg.setText("Non sono stati trovati terremoti avvenuti tra il " + 
        str(rangeInizio) + " e il " + str(rangeFine))
    countMsg.show()

    QgsProject.instance().addMapLayers([terremotiRitagliati])
    QgsProject.instance().addMapLayers([aRispettoLayer])
    
    
    iface.mapCanvas().zoomToSelected()

The last code rows are salient. The problem is attribute "Anno" doesn't update, so the attributes table of the layer "terremotiRitagliati" shows all values of column "Anno" as NULL. Why happens that?

1
  • Is it possible for you to share your data .shp and .gpkg? Otherwise, check the spacing, I do not like that everything is outside the with edit(terrSelezionati):
    – Taras
    Commented Jun 11 at 17:48

1 Answer 1

0

Doing changeAttributeValue() and then updateFeature() resets the feature's attribute values inside the layer meaning that you override your updated value with the previous one, doing nothing.

x = QgsVectorLayer("Point", "test", "memory")
x.dataProvider().addAttributes([QgsField("test", QVariant.String, "", 10)])
x.updateFields()

f =QgsFeature.new(x.fields(), QgsGeometry.from_point(QgsPointXY(1,1)), {"test": "A"})
x.add_features([f])

print(f["test"]) 
# --> "A"

# Your code
with edit(x):
    f = next(x.getFeatures())
    x.changeAttributeValue(f.id(), x.get_field_index("test"), "B")
    x.updateFeature(f)
print(next(x.getFeatures())["test"])
# --> A

# What you need
with edit(x):
    f = next(x.getFeatures())
    x.changeAttributeValue(f.id(), x.get_field_index("test"), "B")
print(next(x.getFeatures())["test"])
# --> B

# or 
with edit(x):
    f = next(x.getFeatures())
    f["test"] = "B"
    x.updateFeature(f)
print(next(x.getFeatures())["test"])
# --> B

Either works.

So, I think it would work for you by changing:

        terremotiRitagliati.startEditing()
        for g in terremotiRitagliati.getFeatures():
            if confronto == g['id']:
                terremotiRitagliati.changeAttributeValue(g.id(), indCampo , el['Anno'])
                terremotiRitagliati.updateFeature(g)
                print(g["Anno"])
        terremotiRitagliati.commitChanges()

by remove the updateFeature call

        terremotiRitagliati.startEditing()
        for g in terremotiRitagliati.getFeatures():
            if confronto == g['id']:
                terremotiRitagliati.changeAttributeValue(g.id(), indCampo , el['Anno'])
                print(g["Anno"])
        terremotiRitagliati.commitChanges()

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