2

I have hundreds of layers that I would like to apply a graduated symbology using the Natural Jenks Algorithm for each. If I copy and paste a style for the layer group the classes and colors are the same because it doesn't update the classes or randomly pick a color for the selected layer. I have tried running 'set layer style' as a batch process with a style file (*.qml), but it also produces the same result as the copy/paste method.

Below is the type of result I would like. Each cluster is a separate layer.

enter image description here

1 Answer 1

4

We can load a saved qml style and apply it to each layer. While applying it we can modify the Color to be a random values.

The script below works as follows:

  1. Apply the saved .qml style (with jenks etc) to the active layer (change the uri)
  2. Loop through each layer and clone the style to that layer
  3. Modify the Start color variable for each layer, calculate the class breaks, and refresh the layer
from random import randrange

#load source of rendering:
uri = ".../Documents/BelcoStyle.qml"
sourcelayer = iface.activeLayer()
sourcelayer.loadNamedStyle(uri) 
classcount = len([s.color() for s in sourcelayer.renderer().symbols(QgsRenderContext())])
renderer = sourcelayer.renderer()
renderer.updateClasses(sourcelayer,classcount)
print(renderer.sourceColorRamp().color1().getRgb() )
sourcelayer.reload()

i=0
#loop through each layer in the project
for layer in QgsProject.instance().mapLayers().values():
    #ignore not vector layers and the source layer
    if isinstance(layer, QgsVectorLayer)and layer.name()!= sourcelayer.name():
        i+=1
        print('\n'+'RUN:%s, '%str(i)+layer.name())
        #
        #get layers by name
        destlayer = layer
        print(destlayer.name())
        #
        #clone renderer from source layer to current layer
        rendervar= renderer.clone()
        print(rendervar.sourceColorRamp().color1().getRgb() )
        destlayer.setRenderer(rendervar) 
        #
        #CHANGE Start colour randomly
        color1 = QColor (randrange(255), randrange(255), randrange(255))
        color2 = QColor (255, 255, 255)
        destlayer.renderer().updateColorRamp(QgsGradientColorRamp(color1, color2))
        destlayer.renderer().updateClasses(destlayer,classcount)
        print(rendervar.sourceColorRamp().color1().getRgb() )
        destlayer.reload()

iface.mapCanvas().refreshAllLayers()

Input Output Image

7
  • Thanks for the reply, have cleaned up to remove redundancy. Of course the breaks need updating, will test and amend code.
    – Cushen
    Apr 27, 2023 at 6:02
  • I'm new to using python in qgis: Traceback (most recent call last): File "C:\OSGeo4W\apps\Python39\lib\code.py", line 90, in runcode exec(code, self.locals) File "<input>", line 1, in <module> File "<string>", line 8, in <module> NameError: name 'renderer' is not defined
    – MJM
    Apr 27, 2023 at 14:16
  • 1
    I've fixed the code, modified the start. I had edited a lined by mistake when editing the content. We need the line: renderer = sourcelayer.renderer()
    – Cushen
    Apr 27, 2023 at 23:13
  • 2
    @MJM you can simply switch color1 and color2 in QgsGradientColorRamp(color1, color2) to invert the ramp.
    – Matt
    Apr 28, 2023 at 16:02
  • 1
    You can change the for loop to be something like: 'for layer in iface.layerTreeView().selectedLayers():' gis.stackexchange.com/questions/152537/… gis.stackexchange.com/questions/450992/…
    – Cushen
    May 1, 2023 at 23:17

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.