Callouts Line Style – Using PyQGIS for Custom Labeling in QGIS 3

labelingpyqgis-3qgis-3

I'm trying to change colors and width of callouts using PyQGIS. Here is example of what i am trying to do :

enter image description here

Here is my code to configure the labelling, including the callouts :

Stations_MF_copy_settings = QgsPalLayerSettings()

# Background
background_color = QgsTextBackgroundSettings()
background_color.setEnabled(True)
background_color.setFillColor(QColor('white'))
background_color.setStrokeWidth(0.8)
background_color.setStrokeColor(QColor("yellow"))
background_color.setSize(QSizeF(2,2))

# Text
text_format = QgsTextFormat()
text_format.setFont(QFont("MS Shell Dlg 2"))
text_format.setSize(12.5)
text_format.setColor(QColor("black"))
text_format.setFont(QFont("MS Shell Dlg 2",11,QFont.Bold))
text_format.setBackground(background_color)

# Callouts
callouts = QgsManhattanLineCallout()
callouts.setEnabled(True)
callouts.setOffsetFromAnchor(2.5)
callouts.setlineSymbol()
Stations_MF_copy_settings.setCallout(callouts)

# Label
Stations_MF_copy_settings.setFormat(text_format)
Stations_MF_copy_settings.isExpression = True
Stations_MF_copy_settings.fieldName = '''concat('Station: ' + to_string("''' + "Nom" + '''"),'\nNĀ° : ' + to_string("''' + "Numero" + '''"),)'''
Stations_MF_copy_settings.enabled = True

Stations_MF_copy_settings.placement = 1
Stations_MF_copy_settings.quadOffset = 5
Stations_MF_copy_settings.xOffset = 5.0
Stations_MF_copy_settings.yOffset = -30.0

Stations_MF_copy_settings = QgsVectorLayerSimpleLabeling(Stations_MF_copy_settings)
Stations_MF_copy.setLabelsEnabled(True)
Stations_MF_copy.setLabeling(Stations_MF_copy_settings)

iface.layerTreeView().refreshLayerSymbology(Stations_MF_copy.id())
Stations_MF_copy.commitChanges()
Stations_MF_copy.triggerRepaint()
QgsProject.instance().removeMapLayers( [layer.id()] )

I learned from the QGIS API documentation that i can use the "setLineSymbol" function that takes QgsLineSymbol as parameter but i can't find how to link it to the QgsManhattanLineCallout class.

Best Answer

QgsLineSymbol inherits the method setColor() from the QgsSymbol base class. And QgsManhattanLineCallout inherits setLineSymbol() from QgsSimpleLineCallout.

So just do:

line_symbol = QgsLineSymbol()
line_symbol.setColor(QColor('Yellow'))
callouts.setLineSymbol(line_symbol)

If you want to alter other callout properties you can use the following approach:

...
line_symbol = QgsLineSymbol()
props = line_symbol.symbolLayers()[0].properties()
# print(props) to check property keys and values
# change any properties you want to modify
props['line_color'] = 'Blue'
props['line_style'] = 'dash'
callouts.setLineSymbol(QgsLineSymbol.createSimple(props))

settings.setCallout(callouts)

labels = QgsVectorLayerSimpleLabeling(settings)
layer.setLabeling(labels)
layer.setLabelsEnabled(True)

layer.triggerRepaint()
iface.mapCanvas().refresh()

To make it a bit easier to apply certain settings, you can also adjust the callout style via the gui, then access their line symbol properties to check key/ value names etc.

l = iface.activeLayer()
lbl = l.labeling()
settings = lbl.settings()
callouts = settings.callout()
symbol = callouts.lineSymbol()
props = symbol.symbolLayers()[0].properties()
print(props) 
Related Question