3

I have encountered a categorised polygon file representing geological units (hundreds of unique categories). The polygon file contains two fields, one for controlling a simple fill colour, the other for controlling an overlying textural pattern. There are symbol sets for each.

The intended cartographic representation of this in a project is to have the same data as duplicated layers, with the simple fill below the textured layer and thus a combined appearance is the intended output on a published map.

While this works in terms of a map output it creates a couple of issues including the problem of creating a legend showing the combined symbology for each geological category.

An obvious solution is to combine the two component symbologies into a new symbol set. However, this would be a big task to do manually as I am not aware of a tool to simply merge symbols. Does anyone know of a simple solution for this problem?

1 Answer 1

3

A PyQGIS solution:

The layer tree

It contains the 'simple fill' (or background) layer, the layer with the overlaying symbol, and a third layer (duplicate of 'simple fill' layer) which will receive the merged symbol - this layer should have Single Symbol symbology to start.

enter image description here

The script
# the current project
p = QgsProject.instance()

# the layer with the simple fill symbology - change the name according to your project
lyr1 = p.mapLayersByName('polygons (simple fill)')[0]

# the layer with the overlaying symbology - change the name according to your project
lyr2 = p.mapLayersByName('polygons (overlay)')[0]

# a duplicate of either lyr1 or lyr2 (set to single symbol) - will receive the merged symbology - change the name according to your project
lyr3 = p.mapLayersByName('polygons (target symbol)')[0]

# get the renderer to merge
source_renderer = lyr2.renderer()

# clone the renderer from 'simple fill' layer ready to accept merged symbol
target_renderer = lyr1.renderer().clone()

# get categories of source and target renderers
cats_source = source_renderer.categories()
cats_target = target_renderer.categories()

# loop through categories and merge symbols
for i,cat in enumerate(cats_target):
    # the symbol of the source layer
    sym_source = cats_source[i].symbol()
    
    # the symbol of the target layer
    sym_target = cats_target[i].symbol()
    
    # append the symbol layer from source to target
    sym_target.appendSymbolLayer(sym_source.symbolLayers()[0])
    
    # update the category's symbol
    target_renderer.updateCategorySymbol(i, sym_target)

# apply the merged renderer to the target layer
lyr3.setRenderer(target_renderer)

# propogate changes to QGIS GUI
lyr3.triggerRepaint()
lyr3.emitStyleChanged()
Result

enter image description here

⚠️ Warning ⚠️

Run the script only once. Running it again will crash QGIS due to mismatches between the original and new symbols.

4
  • Hi Matt, many thanks for your help. Your instructions are very clear. I have got down to the loop and all 3 layers are set up correctly. However, I am having trouble once I enter the loop and get the following error: File "<string>", line 28, in <module> TypeError: list indices must be integers or slices, not tuple. Line 28 code is: sym_source = cats_source[i].symbol(). Could you please check whether there is a typo or something incorrect? Thanks again, Colin Dec 10, 2022 at 10:58
  • Hi Colin, I am currently away from my computer, but I will gladly check later today
    – Matt
    Dec 10, 2022 at 11:13
  • Hi Matt, problem solved and works a treat. My issue related to not having the duplicate layer symbolised as single symbol before I ran the script. Thank you very much, you are a gem! Dec 10, 2022 at 22:27
  • I should have made that more clear in my preamble. I'm glad you got it working.
    – Matt
    Dec 12, 2022 at 19:47

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.