1

I am trying to update a field in a (Road centerline) table based on a value from another table when it is within a Polygon (Locality boundaries).

Based on posts like QGIS layer.geometry.intersection() not finding intersections between layers I have the following code. Both datasets are in EPSG:28355. It never prints ntext=b['Locality_N'] - so obviously something is wrong with the if within statement.

    import re

    def Update_Field(fieldName, ntext): # Function to simplify updating fields
        print (ntext)
        fieldIndex = layer.fields().indexFromName(fieldName)
        dpr.changeAttributeValues({f.id(): {fieldIndex: ntext}})
        layer.commitChanges()

    RoadType_dict = {'Rd':'Road', 'Avenue': 'Ave'}
    layer = iface.activeLayer()
    selection = layer.getFeatures() #all features
    #selection = layer.selectedFeatures() #only selected features

    #Locality Data
    Locality_layer=QgsVectorLayer(r'Z:\My Drive\Mangoesmapping\Spatial Projects\Gen_Library\DSC\vector\DSC_Localities_areas.shp', "Locality", "ogr")

    dpr = layer.dataProvider()

    for f in selection:
        print (f.id())
        text=f['RoadMntnc']
        print (text)
        stext=re.split('_+', text)

    ##Update Road Type
    #    ntext=RoadType_dict.get(stext[-1:][0])
    #    fieldName='Type'
    #    Update_Field(fieldName,ntext)

    ##Update LocalityName
        for b in Locality_layer.getFeatures():
            if f.geometry().within(b.geometry()):
                print (b.geometry())
                ntext=b['Locality_N']
                fieldName="Locality"
                Update_Field(fieldName,ntext)

    layer.commitChanges()
    layer.updateFields()

I have commented out the code that works but is not required for these tests.

--- Based on another answer I also tried

e = QgsExpression( "geomwithin('Locality_layer','Locality_N') ")
f[fieldName] = e.evaluate()
layer.updateFeature(f)

But the values aren't updated in the table.

GeorgeC
  • 8,228
  • 7
  • 52
  • 136
  • 1
    Hi George, I'm not sure if I'm reading your problem correctly, but I'm wondering if you need to nest your for loops - at the moment it looks as though your for b loop loops through everything in your Locality_layer but it only tests one geometry from 'f'? – ian Aug 09 '19 at 12:25
  • @Ian I considered this but since this is within the for loop -- for f in selection: -- wouldn't this be enough? or is this different because it's just attributes and we would need to run a .geometry() loop for both? Basically all it's supposed to do for each road segment is to check which locality (polygon) it's in and fill in the locality column with this value. – GeorgeC Aug 09 '19 at 12:35
  • 1
    yes you're right it is nested already! Just had a look at the answer you've linked to and the format of the if statement is slightly different to yours 'a.geometry.intersects(b.geometry())' have you tried removing the brackets from after f.geometry? – ian Aug 09 '19 at 12:43
  • Thanks - I now get -- AttributeError: 'builtin_function_or_method' object has no attribute 'within'-- I also tried it with 'intersects' instead. – GeorgeC Aug 09 '19 at 13:00
  • @GeorgeC - Sorry, the expression should be in string: e = QgsExpression( "geomwithin('Locality_layer','Locality_N') ") – Joseph Aug 09 '19 at 13:01
  • @Joseph -thanks now there are no failures but the values aren't updated in the table. – GeorgeC Aug 09 '19 at 13:09
  • 1
    @GeorgeC - Does it work if you use the expression geomwithin('Locality_layer','Locality_N') in the field calculator? – Joseph Aug 09 '19 at 13:12
  • 1
    Yes but I had to add the layer to the canvas -it wasn't enough to just call it and it also needed to be the name used in QgsVectorLayer(...) Happy to accept an answer that you post if you want to. – GeorgeC Aug 09 '19 at 13:23

1 Answers1

1

After ensuring you loaded your vector layer, you could use the following:

##Update LocalityName
e = QgsExpression( "geomwithin('Locality','Locality_N') ")
f[fieldName] = e.evaluate()
layer.updateFeature(f)
Joseph
  • 75,746
  • 7
  • 171
  • 282