2

I am using PyQGIS within my work and I currently have a script that uses QgsGraduatedSymbolRenderer to symbolise my data. Previously, I have used a script that symbolises my data using CategorizedSymbolRenderer (see script below). However, this prints out too many values on my exported map, so I have decided to use Graduated instead, so that I can use min/max values to classify my data.

default_style = QgsStyle().defaultStyle()
color_ramp = default_style.colorRamp('Spectral')  # Spectral color ramp
color_ramp.invert()

layer = QgsProject().instance().mapLayersByName('Intensity')[0]

exp_string = '\'Intensity: \' || "Intensity" || \'\nAffected Population: \' || sum("LAC_Popu_1", "Intensity")'
unique_values = []
exp = QgsExpression(exp_string)
#print(exp.isValid())
context = QgsExpressionContext()
context.appendScope(QgsExpressionContextUtils.globalScope())
context.appendScope(QgsExpressionContextUtils.projectScope(QgsProject.instance()))
context.appendScope(QgsExpressionContextUtils.atlasScope(None))
context.appendScope(QgsExpressionContextUtils.layerScope(layer))
exp.prepare(context)
for feat in layer.getFeatures():
    context.setFeature(feat)
    val = exp.evaluate(context)
    if val not in unique_values:
        unique_values.append(val)
# print(unique_values)

categories = []
for value in sorted(unique_values):
    symbol = QgsSymbol.defaultSymbol(layer.geometryType())
    category = QgsRendererCategory(value, symbol, str(value))
    categories.append(category)
renderer = QgsCategorizedSymbolRenderer(exp_string, categories)
renderer.updateColorRamp(color_ramp)
layer.setRenderer(renderer)
layer.setOpacity(0.55)
layer.triggerRepaint()

enter image description here

My script that I have created so far retrieves intensity data from a field called 'Intensity' within my vlayer and uses Graduated Symbology to say if the intensity is between 1.0 - 1.99 for example, then a blue colour is given. This script runs perfectly fine to produce graduated intensity values with corresponding colour. However, I am struggling to get the 'Affected Population' factor within my label, like previously shown, where a value is underneath each intensity. The affected population field will have no involvement as to how the graduated symbology is laid out, it is just extra information for each intensity. This script is as follows:

Intensity_rules = (
    ('MMI Intensity 1.0 - 1.99', 0.0, 1.99, '#2b83ba'),
    ('MMI Intensity 2.0 - 2.99', 2.0, 2.99, '#71b4ae'),
    ('MMI Intensity 3.0 - 3.99', 3.0, 3.99, '#abdda4'),
    ('MMI Intensity 4.0 - 4.99', 4.0, 4.99, '#d4eeb1'),
    ('MMI Intensity 5.0 - 5.99', 5.0, 5.99, '#ffffbf'),
    ('MMI Intensity 6.0 - 6.99', 6.0, 6.99, '#fed58e'),
    ('MMI Intensity 7.0 - 7.99', 7.0, 7.99, '#fdae61'),
    ('MMI Intensity 8.0 - 8.99', 8.0, 8.99, '#ee7144'),
    ('MMI Intensity 9.0 - 9.99', 9.0, 9.99, '#d7191c'),
    ('MMI Intensity 10.0 - 10.99', 10.0, 10.99, '#d7191c'),
)

# create a category for each item in intensity
ranges = []
for label, lower, upper, color in Intensity_rules:
    symbol = QgsSymbol.defaultSymbol(vlayer.geometryType())
    symbol.setColor(QColor(color))
    rng = QgsRendererRange(lower, upper, symbol, label)
    ranges.append(rng)

#create the renderer and assign it to layer
expression = '"Intensity" ' #field name '\'Intensity: \' || "Intensity" || \'\nAffected Population: \' || sum("LAC_Popu_1", "Intensity")'
renderer = QgsGraduatedSymbolRenderer(expression, ranges)
vlayer.setRenderer(renderer)
vlayer.setOpacity(0.70)
vlayer.triggerRepaint()

enter image description here

I run zonal statistics on the intensity shapefile layer, along with a population raster, to produce an affected population column called "LAC_Popu_1". Is there a way I can add this column of produced statistics underneath each line of intensity like in this first script/photo where I used Categorized symbology e.g. MMI Intensity 1.0 - 1.99: 'Blue colour' Affected Population: 545432

4
  • Where does 545432 value come from? – Kadir Şahbaz Mar 12 at 12:49
  • Hi Kadir, I have just used '545432' as an example of the affected population. It could be any number when calculated. This affected population is under the field column called "LAC_Popu_1". Thanks. – LiamHems Mar 12 at 13:02
  • 1
    Do you want the sum of the affected population for every class ? Like : MMI Intensity 1.0 - 1.99: 'Blue colour' Affected Population: 545432 MMI Intensity 2.0 - 2.99: 'Light Blue colour' Affected Population: 70000 etc... Or do you want the affected for every circle even if it's the same class ? If you have n circle you have n value : MMI Intensity 1.0 - 1.99: 'Blue colour' Affected Population: 270000 ,275432 MMI Intensity 2.0 - 2.99: 'Light Blue colour' Affected Population: 30000,20000,10000,10000 – JULESG Mar 12 at 15:47
  • Hi @JULESG , I would like the sum of the affected population for every class, if that is okay! So for just MMI Intensity 1.0 - 1.99, there is only one affected population value with it. And for 2.0 - 2.99, only one affected population value with it too. Hope this makes sense! (the first option you gave in your question). – LiamHems Mar 12 at 16:06
3
+100

To obtain something like this :

Result

You can do a loop in your layer to sum the affected population by class :

minimum = 1
maximum = 10.99
n = 1
result = []
while n < maximum :
    total = 0
    select_features = QgsExpression( "{intensity_field} >= '{lower}' and {intensity_field} < '{upper}'".format(intensity_field = "Intensity", lower = n, upper = n+1))
    for f in vlayer.getFeatures(QgsFeatureRequest( select_features )):
        attrs = f.attributes()
        value = attrs[vlayer.fields().indexFromName("LAC_Popu_1")]
        total = total + value
    result.append(total)
    n = n + 1

You now have a list, result, with every sum for every class with index(0) is the first class and index(-1) the last.

You can modify your rules to add the sum to your label :

    Intensity_rules = (
    ('MMI Intensity 1.0 - 1.99' + '\n Affected Population : ' + str(result[0]), 0.0, 1.99, '#2b83ba'),
    ('MMI Intensity 2.0 - 2.99' + '\n Affected Population : ' + str(result[1]), 2.0, 2.99, '#71b4ae'),
    ('MMI Intensity 3.0 - 3.99' + '\n Affected Population : ' + str(result[2]), 3.0, 3.99, '#abdda4'),
    ('MMI Intensity 4.0 - 4.99' + '\n Affected Population : ' + str(result[3]), 4.0, 4.99, '#d4eeb1'),
    ('MMI Intensity 5.0 - 5.99' + '\n Affected Population : ' + str(result[4]), 5.0, 5.99, '#ffffbf'),
    ('MMI Intensity 6.0 - 6.99' + '\n Affected Population : ' + str(result[5]), 6.0, 6.99, '#fed58e'),
    ('MMI Intensity 7.0 - 7.99' + '\n Affected Population : ' + str(result[6]), 7.0, 7.99, '#fdae61'),
    ('MMI Intensity 8.0 - 8.99' + '\n Affected Population : ' + str(result[7]), 8.0, 8.99, '#ee7144'),
    ('MMI Intensity 9.0 - 9.99' + '\n Affected Population : ' + str(result[8]), 9.0, 9.99, '#d7191c'),
    ('MMI Intensity 10.0 - 10.99' + '\n Affected Population : ' + str(result[9]), 10.0, 10.99, '#d7191c'),
)
1
  • Thank you very much for your help! That is exactly what I wanted :) – LiamHems Mar 12 at 16:44

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.