I have a vector layer with two columns: Code (string) and Area (float/double). The column Code includes some repeated values. I'd like to evaluate for each unique value of Code the maximum value of the Area values which are associated. Similar questions but with different approaches, not suitable with my need, are at Selecting Maximum value for each unique ID ; How can I create a numeric field (not ObjectID) with a unique number for each record?. I made some trials but they don't work at all...any suggestions?


First of all, based on other posts in the forum (Maximum value of vector layer field in PyQGIS), I tried to implement a script for just calculating the maximum value of the field "Area". It returns 3071.96126727

values = []
    for feat in layer.getFeatures():
       attrs = feat.attributes()
    print max(values)


Then, I tried to insert the previous script into another one for identifying and iterating on unique values. The problem is that it returns a list of the unique values associated only to the maximum value of the whole field Area i.e. [u'aa1014551', u'ab1014552', etc...] 3071.96126727

for uv in uniquevalues:
    values = []
    for feat in layer.getFeatures():
        attrs = feat.attributes()
    maximum=max(values) #it also has such a temporaly stuck here
    print uniquevalues, maximum
  • You should add a conditional before values.append to limit to the actual unique value: if attrs[code_index] == uv: In the print statement you should print uv, maximum – Zoltan May 18 '17 at 13:12
  • Thanks, good and cleat answer! So, the code becomes: uniquevalues=layer.uniqueValues(code_index,limit=10000) for uv in uniquevalues: values = [] for feat in layer.getFeatures(): attrs = feat.attributes() if attrs[code_index] == uv: values.append(attrs[area_index]) maximum=max(values) #indentation needed for printing all data print uv, maximum Just an issue, the code prints all unique values with associated area BUT there are some repeted values...how is it possible? – FedericaZ May 22 '17 at 8:04

Just as last month on your question Sum values of a field based on unique values in another field, you need to select the features corresponding to your unique value instead of using the entire layer. You can find more examples in the PyQGIS cookbook.

layer = iface.activeLayer()
for uv in uniquevalues:
    values = []

    #statement for selecting just the proper buildings
    exp = QgsExpression('BUILDING = ' + str(uv))
    request = QgsFeatureRequest(exp)
    #Select only the buildings having the specified value

    for feat in featuresforthisuniquevalue:
        attrs = feat.attributes()
    maximum=max(values) #Now it is the max just for this unique value
    print uv, maximum #print for ONE unique value, not the list
  • Hi @JHG, thank you so much for the reminder! (Of course, I know but I supposed there was some difference and I was having some trouble) Anyway, at line featuresforthisuniquevalue=layer.getFeatures(request), the following message is returned: Traceback (most recent call last): File "<input>", line 1, in <module> AttributeError: 'int' object has no attribute 'getFeatures' ...any suggestion about that? – FedericaZ May 22 '17 at 8:45
  • I added the line for getting the active layer, though you can use any layer. The error message means the layer variable was not set to a layer, maybe just a layer ID? – JGH May 22 '17 at 12:29
  • GREAT! YOU'RE RIGHT! actually in place of layer=iface.activeLayer() I had written sommething like this: layer=QgsVectorLayer(r'C:/path/name.shp',"name","ogr") and of course it works. Regarding the mistake, as you suggested then I wrongly wrote something like: field.getFeatures in place of layer.getFeatures THANK YOU SO MUCH! :D – FedericaZ May 22 '17 at 12:37
  • If I can point out something (even if for many people it could be obvious): if I write the lines <<maximum=max(values)>> and <<print uv, maximum>> as indented within the "for" cycle, it is possible to have the whole list of unique values and associated max areas. – FedericaZ May 22 '17 at 12:45

If I understand your question, this code should work well:

layer = iface.activeLayer() # load the layer as you want
max_values = {}
unique_val_field = "Code" # set the name for the field containing the codes
vals_field = "Area" # set the name for the field containing the area values

for feat in layer.getFeatures():
    if feat[unique_val_field] not in max_values.keys():
        max_values[feat[unique_val_field]] = feat[vals_field]
        if feat[vals_field] > max_values[feat[unique_val_field]]:
            max_values[feat[unique_val_field]] = feat[vals_field]

It will return the max_values dictionary which stores the max value for every single code. I performed a quick test with codes ranging from 1 to 10 and random area values, and this is the result:

print max_values

{u'10': 799.89318522, u'1': 764.34522538, u'3': 794.76607562, u'2': 793.07840205, u'5': 795.87694937, u'4': 793.22794275, u'7': 795.77013459, u'6': 798.93185217, u'9': 793.5483871, u'8': 796.34693442}

as expected.

  • such interesting! But eventually, how can I select (and then print) the values "on the right of" the dictionary in one attribute table field? – FedericaZ May 22 '17 at 12:51
  • @FedericaZ I think this answer on Stack Exchange should offer a good explanation on how to iterate over the keys and the values of a dictionary. If you want to loop only over the keys, you may use max_values.keys() (see my code above); if you want to loop only over the values, you may use max_values.values() in a similar way. – mgri May 22 '17 at 13:29

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.