9

I have a PyQGIS script to open a GPKG-layer (contour lines) along with a qml-file in QGIS. In the style file I have enabled label masking and using the contour lines as mask layer:

enter image description here

enter image description here

Making my labels look like this:

enter image description here

However, after running the python-file, the style is as expected (as given in the qml-file), but without the masking (label masking information is not stored in the qml-file?):

enter image description here

My code so far where I have not figured out how to set "Masked symbol layers" and "Mask sources":

# Add geopackage
fileName = "karplantehoyder.gpkg"
layer = QgsVectorLayer(fileName, "hoyder", "ogr")
label = QgsPalLayerSettings()
label.MaskEnabled = True
# masklayer = QgsMaskMarkerSymbolLayer()  #? How do i set the mask symbol layer and mask source
# masklayer.setMasks("hoyder")            # This is not working, have tried id and layer - not working
QgsProject.instance().addMapLayer(layer, True) 
# Load style
layer.loadNamedStyle('./qml/n5hoyder.qml')  # color, line width, label font/size set, but not mask
layer.saveStyleToDatabase(layer.name(),'style n5hoyder',True,'')

How may I do this with PyQGIS-code?

Update: I have also tried to use QgsTextMaskSettings, but I can't figure out how to set the mask layer to be "hoyder" and symbol to be lines.

I have also discovered a strange behaviour? Masks may be set in the layer hoyder's Layer Properties and still be unchecked in Layer styling, and the mask will appear.

enter image description here

If only set in the Layer Styling and not in the Layer Properties, the mask will not appear.

enter image description here

2
  • This post may help you.
    – Mayo
    Dec 12, 2022 at 15:55
  • @Mayo, thanks for the link which I already had a look at. The post is from 2019 while masking came in 3.12 released 2020-02-21, I believe. I could not find anything regarding mask in the code in the post, and besides, my labels appear. Just the mask is missing. qgis.org/en/site/forusers/visualchangelog312/…
    – 9ls1
    Dec 12, 2022 at 16:18

2 Answers 2

10
+100

Label masking information is not stored in the qml-file?

I guess "Masked symbol layers" and "Mask sources" settings are not stored in both qml file and Geopackage. I just realized that.

One solution would be as follows:

  • Load qml file
  • Get layer labeling mask settings
  • Set masked symbol layers
  • Apply the setting to the layer
# Add layer
fileName = "karplantehoyder.gpkg"
layer = QgsVectorLayer(fileName, "hoyder", "ogr")
QgsProject.instance().addMapLayer(layer, True) 

# Load qml
layer.loadNamedStyle('./qml/n5hoyder.qml')

# Get current settings of the layer
label_settings = layer.labeling().settings()
# If you use labeling() method before loading qml, you get error
# Because labeling is not enabled for the layer before loading qml


# Get text format of the settings
text_format = label_settings.format()

# Set masked symbol layers
text_format.mask().setMaskedSymbolLayers([
    QgsSymbolLayerReference(layer.id(), QgsSymbolLayerId("", 0))])

# Set format
label_settings.setFormat(text_format)

# Set settings
layer.labeling().setSettings(label_settings)

enter image description here

Documentation:

2
  • 1
    Excellent! Nicely explained to a pyQGIS newbie like me. Works like a charm. Now, I finally see what setMaskedSymbolLayers(self, maskedLayers: Iterable[QgsSymbolLayerReference]) means and how to assign the parameters. This will hopefully help me in the future when reading QGIS API documentation. Thanks!
    – 9ls1
    Dec 15, 2022 at 11:13
  • Unfortunately, the class QgsSymbolLayerReference has changed in QGIS ver. 3.30 (qgis.org/pyqgis/3.30/core/…). Thus the code above don't work in ver. 3.30. So far I haven't figured out how to change the code to make it work.
    – 9ls1
    Apr 26, 2023 at 12:22
3

Update QGIS ver. 3.30 (see thread on https://lists.osgeo.org/pipermail/qgis-user/2023-April/052905.html)

You may still use the code from Kadir Şahbaz above, but you need to add two procedures and change the code-line for setting the mask (****).

This is working for me in ver. 3.30:

def get_symbollayer(layer, ruleId, symbollayer_ids):
    """
    Returns the symbol layer according to given layer, ruleId (None if no rule) and the path
    to symbol layer id (for instance [0, 1])
    """
    renderer = layer.renderer()
    symbol = None
    if renderer.type() == "categorizedSymbol":
        i = renderer.categoryIndexForValue(ruleId)
        cat = renderer.categories()[i]
        symbol = cat.symbol()
    elif renderer.type() == "singleSymbol":
        symbol = renderer.symbol()

    symbollayer = symbol.symbolLayer(symbollayer_ids[0])
    for i in range(1, len(symbollayer_ids)):
        symbol = symbollayer.subSymbol()
        symbollayer = symbol.symbolLayer(symbollayer_ids[i])

    return symbollayer

def get_symbollayer_ref(layer, ruleId, symbollayer_ids):
       """
       Returns the symbol layer according to given layer, ruleId (None if no rule) and the path
       to symbol layer id (for instance [0, 1])
       """
       symbollayer = get_symbollayer(layer, ruleId, symbollayer_ids)
       return QgsSymbolLayerReference(layer.id(), symbollayer.id())

...

fileName = "./gpkg/karplantehoyder.gpkg"
layer = QgsVectorLayer(fileName, "hoyder", "ogr")
layer.loadNamedStyle('./qml/n5hoyder.qml')      # Load qml
QgsProject.instance().addMapLayer(layer, False) # Add layer False to be able
root.insertLayer(4,layer)                       # to specify a custom position
label_settings = layer.labeling().settings()    # Get current settings of the layer
text_format = label_settings.format()           # Get text format of the settings
text_format.mask().setMaskedSymbolLayers([get_symbollayer_ref(layer,"",[0])])  # set masked symbol layers ****

...

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.