2

I have a QGIS project with various point and line layers, some with a categorized symbology and one line layer with line markers. I'm trying to create a simple Python script to quickly change the size/width of the point/line markers in all of these layers, in order to be able to make clear maps. My script currently looks like this:

from qgis.core import QgsProject

# Enter scaling factor here
scale_factor = 2

# Symbol scaling function
def scale_symbol(scl, sym, lrn, ind):
    new_symbol = sym.clone()
    
    # Change size of point symbols
    if new_symbol.type() == QgsSymbol.Marker:
        new_symbol.setSize(new_symbol.size() * scl)
        print("Symbol rescaled for layer", lrn[ind])
        print("New symbol size:",new_symbol.size(), new_symbol.outputUnit())
        
    # Change width of line symbols
    elif new_symbol.type() == QgsSymbol.Line:
        new_symbol.setWidth(new_symbol.width() * scl)
        print("Symbol rescaled for layer", lrn[ind])
        print("New symbol width:",new_symbol.width(), new_symbol.outputUnit())
        
        # Change size of line marker symbols
        if new_symbol.symbolLayerCount() > 1:
            marker_layer = new_symbol.symbolLayer(1)
            marker_layer.setWidth(marker_layer.width() * scl)
            print("Symbol rescaled for layer", lrn[ind], "(markers)")
            print("New symbol size:",marker_layer.width(), new_symbol.outputUnit())
    
    return new_symbol


project = QgsProject.instance()
# List of layers to be rescaled
layer_names = ['Leidingen_PLAN', 'Putten_PLAN', 'Leiding', 'Put', 'Lozing_Inlaat', 'HC_ref_deksel']

# Get renderer for each layer
renderer_list = []
for layer_name in layer_names:
    layer = project.mapLayersByName(layer_name)[0]
    renderer_list.append(layer.renderer())

idx = 0
for renderer in renderer_list:
    print(renderer.type())
            
    # Rescale single symbol layers
    if renderer.type() == 'singleSymbol':
        symbol = renderer.symbol()
        new_symbol = scale_symbol(scale_factor, symbol, layer_names, idx)
        renderer.setSymbol(new_symbol)
     
    # Rescale categorized symbol layers 
    elif renderer.type() == 'categorizedSymbol':
        categories = renderer.categories()
        
        # Loop over symbols of all categories 
        for category in categories: 
            symbol = category.symbol()
            new_symbol = scale_symbol(scale_factor, symbol, layer_names, idx)
            category.setSymbol(new_symbol)
        
    idx += 1

This script works for the single symbol layers (of which I can see the markers change size after running the script), but not for the categorized symbol layers. No error is raised, the print statements show that all renderers, categories and layers are being handeled and their sizes and widths should be changed. Does the .setSymbol() method not affect the symbols when they are in a category of a categorized renderer instead of directly in a renderer? Then what is the correct way to set a new symbol for a categorized symbol layer using PyQGIS? (I'm also open to suggestions for other convenient methods that allow me to change the symbol size for multiple layers at once.)

1 Answer 1

1

You can use the method updateSymbols() of the QgsCategorizedSymbolRenderer class.

With this method, you can change the marker size/ line width while leaving the colours and categories unmodified.

So your script could look like:

from qgis.core import QgsProject

# Enter scaling factor here
scale_factor = 2

# Symbol scaling function
def scale_symbol(scl, sym, lrn, ind):
    new_symbol = sym.clone()
    
    # Change size of point symbols
    if new_symbol.type() == QgsSymbol.Marker:
        new_symbol.setSize(new_symbol.size() * scl)
        print("Symbol rescaled for layer", lrn[ind])
        print("New symbol size:",new_symbol.size(), new_symbol.outputUnit())
        
    # Change width of line symbols
    elif new_symbol.type() == QgsSymbol.Line:
        new_symbol.setWidth(new_symbol.width() * scl)
        print("Symbol rescaled for layer", lrn[ind])
        print("New symbol width:",new_symbol.width(), new_symbol.outputUnit())
        
        # Change size of line marker symbols
        if new_symbol.symbolLayerCount() > 1:
            marker_layer = new_symbol.symbolLayer(1)
            marker_layer.setWidth(marker_layer.width() * scl)
            print("Symbol rescaled for layer", lrn[ind], "(markers)")
            print("New symbol size:",marker_layer.width(), new_symbol.outputUnit())
    
    return new_symbol

project = QgsProject.instance()
# List of layers to be rescaled
layer_names = ['Leidingen_PLAN', 'Putten_PLAN', 'Leiding', 'Put', 'Lozing_Inlaat', 'HC_ref_deksel']

idx = 0

for layer_name in layer_names:
    layers = project.mapLayersByName(layer_name)
    
    if not layers:
        print(f'Layer {layer_name} not found')
        continue
        
    layer = layers[0]
    
    renderer = layer.renderer()
    # Rescale single symbol layers
    if renderer.type() == 'singleSymbol':
        symbol = renderer.symbol()
        new_symbol = scale_symbol(scale_factor, symbol, layer_names, idx)
        renderer.setSymbol(new_symbol)
     
    # Rescale categorized symbol layers 
    elif renderer.type() == 'categorizedSymbol': 
        symbol = renderer.sourceSymbol()
        new_symbol = scale_symbol(scale_factor, symbol, layer_names, idx)
        renderer.updateSymbols(new_symbol)
    
    layer.triggerRepaint()
    iface.layerTreeView().refreshLayerSymbology(layer.id())
    
    idx += 1

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.