2

My aim is to change the layer's name only within the legend - I want to leave the layer itself untouched. I tried multiple variants of X.setName(), both on the vector layer item, the map layer and the LayerTreeLayer and so on, via the model - All of that also changes the layer's name outside the legend, which is not what I want.

I found that within the Print Layout editor, there is actually a way to achieve this - you can click on the legend item, select the one you want to rename, "edit selected item properties", and then just enter the new label text. But how can I do this from code?

This is my code so far, using a rename of the base layer which is what I want to avoid.

legend = QgsLayoutItemLegend(layout)
legend.setTitle("Legend")

# vector_layer.setName("Layer Name in Legend")  # change item name in legend
legend.setAutoUpdateModel(False)  # separates the layout's legend from the project's

legend.setLinkedMap(map)
legend.setLegendFilterByMapEnabled(True)
layout.addLayoutItem(legend)
legend.attemptMove(QgsLayoutPoint(235, 36, QgsUnitTypes.LayoutMillimeters))

I am working in QGIS 3.22.

0

3 Answers 3

3

Looks like you already got a working solution, but here is another approach- passing the layer tree layer object, the index of the root node and the desired label as a string to the setLegendNodeUserLabel() method of the QgsMapLayerLegendUtils class.

layer = QgsProject.instance().mapLayersByName('Layer_Name_In_Project')[0]
lyr_tree_lyr = legend.model().rootGroup().findLayer(layer.id())
legend.setAutoUpdateModel(False)
QgsMapLayerLegendUtils.setLegendNodeUserLabel(lyr_tree_lyr, 0, 'Label name you want in layout legend')
legend.model().refreshLayerLegend(lyr_tree_lyr)
1
  • I actually tried this, but it did not work for me - If you tried it and it did work, I suspect the difference is in the symbology. My layer is a graduated line layer, and index 0 addresses the first of the symbol classes, instead of the layer itself. Maybe it works for a single fill layer, but it is not a viable option for my case.
    – Noxy
    Commented Sep 19, 2022 at 13:07
2

(Hack-ish Workaround - Proper Solution in the Accepted Answer)

After trying it out for a few hours, I finally figured it out. I was on the right path with QgsLayerTreeLayer, however, I was editing the wrong object - basically, still the vector layer itself rather than the legend.

First, ensure that the layout has actually been generated - rather than continuing to work with the created legend item, access the item within the layout:

legend_item = [i for i in layout.items() if isinstance(i, QgsLayoutItemLegend)][0]

(Do comment if there's a better way to get the legend, particularly since there's only one.)

lyr = legend_item.model().rootGroup().findLayer(vector_layer)  # switch from QgsVectorLayer to QgsLayerTreeLayer
lyr.setUseLayerName(False)  # Make the legend use a name different from the layer's

Here's the really important part: We don't want to work with the layer objects saved above - We want those within the legend.

tree_layers = legend_item.model().rootGroup().children()  # get the legend's layer tree
for tr in tree_layers:
    if tr.name() == layer_name: # ensure you have the correct child node
        tr.setName("New Name")  # set the child node's new name
legend_item.updateLegend()  # Update the QgsLayerTreeModel
1

It turns out my previous answer was still just a workaround, and if I edited the legend afterwards, it would realize as much and reset itself. Alas, here is the actual solution, with heavy inspiration from the QGIS API on QgisLayoutItemLegend:

legend = QgsLayoutItemLegend(layout)
legend.setAutoUpdateModel(False)

for tr in legend.model().rootGroup().children():
    if tr.name() == layer_name:
        tr.setCustomProperty("legend/title-label", "new name in legend")

layout.addLayoutItem(legend)

That's it. That is all you actually had to do. No need to worry about the legend being drawn first either.

Not the answer you're looking for? Browse other questions tagged or ask your own question.