3

I'm new to QGIS AND Python.

This is how I'm trying to calculate all areas of the layer named polygons:

def add_area():

layers = QgsMapLayerRegistry.instance().mapLayers().values()
foundlayer = False
for layer in layers:
    if layer.name() == 'polygons':
        inputlayer = QgsMapLayerRegistry.instance().mapLayersByName("polygons")[0]
        print ('polygons-layer found')
        iface.setActiveLayer(inputlayer)
        foundlayer = True
if not foundlayer:
    print ("polygons does not exist")
    #maybe not the most elegant way, but it works till here as it should :-)
area = 0
#this creates me a new column named "Area"
provider = inputlayer.dataProvider()
provider.addAttributes([QgsField("Area",QVariant.Double)])
#and now I'm iterating through all features to calculate each polygons area...
features = inputlayer.getFeatures()
f = features.next()
for f in features:
    attribute = (f.attributes())
    print(attribute)
    calculator = QgsDistanceArea()
    area = calculator.measurePolygon(f.geometry(). asPolygon()[0])
    calculator.convertMeasurement(area, QGis.Degrees, QGis.Meters, True)
inputlayer.updateFields()

Even it creates the new column in the attribute table, I'm getting this Error:

Layer polygons: SQLite error: duplicate column name: Area SQL: ALTER TABLE "polygons" ADD COLUMN "Area"

tried to google it but couldn't find a answer in any forum, that I understand and that help's me solving it.

Do I get the message, because the column "Area" is already created? (that is possible, because I naturally tried my code several times! But I got this message already the first time...!?)

1 Answer 1

2

There's a few things to notice:

  • The code continues regardless if the polygon layer exists or not as there's no else statement.
  • The code adds a new "Area" field each time it is run so you may indeed have multiple fields.
  • f = features.next() is not necessary, for f in features: is enough.
  • The code seems to be calculating the area but not writing it to the field.

The following is your code but slightly modified (I've added some comments to describe what's happening):

def add_area():
    layers = QgsMapLayerRegistry.instance().mapLayers().values()
    foundlayer = False
    for layer in layers:
        if layer.name() == 'polygons':
            inputlayer = QgsMapLayerRegistry.instance().mapLayersByName('polygons')[0]
            print ('polygons-layer found')
            iface.setActiveLayer(inputlayer)
            foundlayer = True
    if not foundlayer:
        print ('polygons does not exist')
    # You need an else statement
    else:
        # Find index of Area field
        idx = inputlayer.fieldNameIndex('Area')
        # if "Area" field does not exist, create it otherwise update the existing field
        if idx == -1:
            provider = inputlayer.dataProvider()
            provider.addAttributes([QgsField('Area',QVariant.Double)])
            # Update fields
            inputlayer.updateFields()                   
        # Get features
        features = inputlayer.getFeatures()
        # Use `with edit(inputlayer)` method to start editing and commit changes in one go
        with edit(inputlayer):
            # Iterate through the features (you do not need `f = features.next()`)
            for feat in inputlayer.getFeatures():
                # Calculate area for each feature
                area = feat.geometry().area()
                # Add the value to the "Area" field for each feature
                inputlayer.changeAttributeValue(feat.id(), idx, area)

Alternatively, the following is code I normally use when finding specific layers and writing values to them (I incorporated some of your code into it):

from PyQt4.QtCore import QVariant

def add_area():
    try:
        inputlayer = QgsMapLayerRegistry.instance().mapLayersByName('polygons')[0]
        print 'polygons-layer found'
        idx = inputlayer.fieldNameIndex('Area')
        if idx == -1:
            provider = inputlayer.dataProvider()
            field = QgsField("Area", QVariant.Double)
            provider.addAttributes([field])
            inputlayer.updateFields()       
        with edit(inputlayer):
            for feat in inputlayer.getFeatures():
                area = feat.geometry().area()
                inputlayer.changeAttributeValue(feat.id(), idx, area)
    except IndexError:
        print 'polygons does not exist'
6
  • 1
    ok, there's definitely a lot I've to work on!... but big thx to you Joseph, you helped me definitely to understand where I was thinking in the wrong direction!
    – Nico
    Commented Aug 2, 2017 at 10:39
  • @Nico - Most welcome and don't worry, you're doing great! :)
    – Joseph
    Commented Aug 2, 2017 at 10:45
  • ok the code works now, but I'm missing the unit 🙈 I checked with one polygon which area I know is somewhere between 410 - 450 square meters, but it shows 7.2E-8... can't find factor here - does someone know which unit it is? thx again for your help guys, really appreciate it!
    – Nico
    Commented Aug 2, 2017 at 13:01
  • @Nico - Be careful of the CRS of the layer, you may need to reproject it to a UTM with units as meters if you want to use the code above.
    – Joseph
    Commented Aug 3, 2017 at 8:54
  • I'm guessing CRS is KBS in German... It is already set to meters and square meters within the wgs84 coordinate system. (oh man, I feel like I'm John Snow, because I know nothing ;P)
    – Nico
    Commented Aug 3, 2017 at 9:57

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.