7

In QGIS 2.18 there is a shapefile with three fields accordingly

id Type Value
1 a 5
2 b NULL
3 c 1
4 d 6
5 e NULL

I want to get the total sum of all values in the field "Value". How can I achieve that in the Python Console?

The field "Value" maintains two types of data int and NULL.

I was trying with a while-loop but it does not work

layer = qgis.utils.iface.activeLayer()

if not layer.isValid():
    raise Exception('Layer is not valid')

features = layer.getFeatures()

for feat in features:
    attr = feat.attributes()[2]
    
    if attr == NULL:
        continue

    else:
        total = 0
        index = 0
        while index < layer.featureCount():
            total = total + int(attr)
            index = index + 1
return(total)

How to achieve one number that gives the total sum of a whole field exclusive NULL-values?

After executing @ahmadhanb's solution I received a correct number but somehow with a strange output type, when print (type(sum(total))) it gives me <type 'NoneType'>. What could be a problem?


References:

5
  • Try to place the print(total) out of the loop. This will give you one value which is the total value.
    – ahmadhanb
    Commented Feb 28, 2019 at 13:10
  • @Taras you can replace print(0) with continue to skip null values.
    – ahmadhanb
    Commented Feb 28, 2019 at 13:17
  • 1
    Taras - What layer and field type is it and which QGIS version are you using? Would it be possible to share a sample of this data online so that others could test it? The one-liner from @Bera works for me in QGIS 2.18 and 3.4.
    – Joseph
    Commented Feb 28, 2019 at 15:37
  • @Taras - Your sample dataset is missing a .shx file so it cannot be loaded.
    – Joseph
    Commented Mar 1, 2019 at 10:28
  • 1
    @Taras - Your sample data works fine if I use int(sum(filter(None,[f['Value'] for f in layer.getFeatures()]))) which returns the value 441.
    – Joseph
    Commented Mar 1, 2019 at 15:39

3 Answers 3

7

In programming, there are several ways of solving a problem.

That's also the case for summing values of a field in QGIS. But there is one that is the recommended way, truly leveraging the PyQGIS API.

Aggregating field values using PyQGIS

To get the sum of a field you can use:

total_sum = layer.aggregate(QgsAggregateCalculator.Sum, "my_field_name")

Simpler and faster.

Note: Since the result is a tuple (result_value, boolean_result), you just call total_sum[0] and you are done.


Read the docs to know the list of aggregate types you can use.

You can even pass filter expressions to the aggregates. Really powerful.


Note: this is available since QGIS 2.16.

9
  • Thank you for such an explicit answer. I just checked and seems like the sum inside the tuple is a float type, is not it?
    – Taras
    Commented May 22, 2021 at 8:23
  • That's right @Taras. Commented May 22, 2021 at 13:29
  • @Taras, is that somehow relevant to you? Commented May 25, 2021 at 14:10
  • thank you, yes it is!
    – Taras
    Commented May 25, 2021 at 14:11
  • @Taras, which answer would you like new users to use? :) Commented Aug 9, 2021 at 16:25
5

In fact your code provides a double number to the actual value. For example, if the total number is 50, your code provides 100. I think the correct code should be something like this:

layer = qgis.utils.iface.activeLayer()

if not layer.isValid():
    raise Exception('Layer is not valid')

features = layer.getFeatures()

total = []
for feat in features:
    attr = feat.attributes()[2]

    if attr == NULL:
        continue

    else:
        total.append((int(attr)))
print(sum(total))

Add a total empty list outside the loop, and if the attr == NULL, it will skip the null values, and if there is a value in the attr it will be appended to the list. Then you can print the sum of the list outside the loop to get one value only.

Here is the screenshot of the output:

enter image description here

4
  • @Taras But I did not write print(type(sum(total))), I wrote print(sum(total)) which will provide an integer value. The output print(type(sum(total))) is <class 'int'> not <type 'NoneType'>
    – ahmadhanb
    Commented Feb 28, 2019 at 13:46
  • That is strange. Why do you get <type 'NoneType'>? I am getting integer output type.
    – ahmadhanb
    Commented Feb 28, 2019 at 14:06
  • Shouldnt if attr == NULL be if attr is None?
    – Bera
    Commented Feb 28, 2019 at 14:11
  • @BERA Using if attr is None gives an error for integer field whereas if attr == NULL works well.
    – ahmadhanb
    Commented Feb 28, 2019 at 14:22
5

In QGIS 3, QgsVectorLayerUtils.getValues() returns all values from a specified field name or expression.

You can use to sum values in one field in that way:

layer = iface.activeLayer()
v = QgsVectorLayerUtils.getValues(layer, 'field_name')[0]
v = list(filter(None, v))
s = sum(v)

NOTE: NULL is None is False (both have different objects in the memory). NULL == None is True (both have the same value). Therefore, we can use None here.

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.