6

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:

8
  • Try to place the print(total) out of the loop. This will give you one value which is the total value.
    – ahmadhanb
    Feb 28 '19 at 13:10
  • It gives one value, but a wrong one...
    – Taras
    Feb 28 '19 at 13:13
  • @Taras you can replace print(0) with continue to skip null values.
    – ahmadhanb
    Feb 28 '19 at 13:17
  • @BERA, a nice one and a right one. But the type(sum(filter(None,[f['Value'] for f in layer.getFeatures()]))) is <type 'function'>. I am willing to have an integer... to be able to worjk with it further.
    – Taras
    Feb 28 '19 at 13:21
  • 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
    Feb 28 '19 at 15:37
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

6
  • Looks promising! The problem is that the output of print(type(sum(total))) is <type 'NoneType'>. I need to use it in some further calculations.
    – Taras
    Feb 28 '19 at 13:43
  • @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
    Feb 28 '19 at 13:46
  • How can I use this value in my further calculations when the type that I do have is <type 'NoneType'>?
    – Taras
    Feb 28 '19 at 13:50
  • That is strange. Why do you get <type 'NoneType'>? I am getting integer output type.
    – ahmadhanb
    Feb 28 '19 at 14:06
  • Shouldnt if attr == NULL be if attr is None?
    – BERA
    Feb 28 '19 at 14:11
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.

5

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
    May 22 at 8:23
  • That's right @Taras. May 22 at 13:29
  • @Taras, is that somehow relevant to you? May 25 at 14:10
  • thank you, yes it is!
    – Taras
    May 25 at 14:11
  • @Taras, which answer would you like new users to use? :) Aug 9 at 16:25

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.