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:

0

3 Answers 3

8

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.

0
6

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

You can use it to sum values in one field in this way:

from qgis.utils import iface
from qgis.core import QgsVectorLayerUtils

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

NOTE:

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

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:

from qgis.utils import iface
from qgis.core import NULL

layer = 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 list sum outside the loop to get only one value.

Here is the screenshot of the output:

enter image description here


References:

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.