12

I would like to update the legend item in my layout with other names.

I tried the following code, which returns no error but layers name remain the same.

project = QgsProject.instance()
layout = QgsPrintLayout(project)
layout.initializeDefaults()

layersToAdd = [puit, puit_m, amas, home, fosse, eau_l, eau_p, pdf] # each layer is defined with mapLayersByName
Names = ['Puit', 'Puit municipal', 'Amas', 'Maison', 'Fossé', 'Cours d\'eau', 'Surface d\'eau', 'Champs']
legend = QgsLayoutItemLegend(layout)
legend.setAutoUpdateModel(False)
root = QgsLayerTree()
tree=legend.model().rootGroup()
i = 0
for layer in layersToAdd:
    #add layer objects to the layer tree
    root.addLayer(layer)
    tree.children()[i].setName(Names[i])
    i += 1
legend.updateLegend()
legend.model().setRootGroup(root)
layout.addLayoutItem(legend)

3 Answers 3

14

You must set setUseLayerName() to False to name legend tree layers manually.

#
# previous lines
#

for i, layer in enumerate(layersToAdd):
    tree_layer = root.addLayer(layer)
    tree_layer.setUseLayerName(False)
    tree_layer.setName(names[i])
    
legend.updateLegend()

...
3
  • Perfect, thank you for the quick answer ! I didn't see this method Jan 21, 2021 at 22:36
  • 1
    Note that if you do that on an existing legend from which you retrieved the rootGroup using root=legend.model().rootGroup(), you will need to set the root group again to the legend otherwise it will not update: legend.model().setRootGroup(root)
    – seb007
    Aug 31, 2022 at 8:47
  • @seb007 that was very important and should be added to answer. Thank's for your note Aug 17 at 8:13
2

There's another way, figured out with heavy inspiration from the QGIS API on QgisLayoutItemLegend:

legend = QgsLayoutItemLegend(layout)
legend.setAutoUpdateModel(False)  # legend derived from the map's layers but now unlinked

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

layout.addLayoutItem(legend)
1

In addition to Kadir Şahbaz answer.

According to comment section, seb007 noticed that names may not be eventually changed if there is no QgsLayerTree update for a legend object. As he posted, there should be a re-setting of legend root:

root=legend.model().rootGroup()
legend.model().setRootGroup(root)

Also in my case I have multiple legend objects in multi-page layout. My experience, github comments and some snippets shown that each QgsLayerTree value for each QgsLayoutItemLegend should be named individually. I.e. if you have a list of legends, QgsLayerTree values have to be different like

self.tree1 = QgsLayerTree()
self.tree2 = QgsLayerTree()
...
self.legend_obj1.model().setRootGroup(self.tree1)
self.legend_obj2.model().setRootGroup(self.tree2)

If the number of legends is different or you want this process to be in a loop, I may recommend to use settattr() and getattr() functions in a class.

for i, legend_settings in enumerate(legend_stack):
    self.legend_obj = QgsLayoutItemLegend(self.layout) # assuming you have layout attribute already
    setattr(self, 'legend_{}'.format(i), QgsLayerTree())
    self.legend_obj.model().setRootGroup(getattr(self, 'legend_{}'.format(i)))

Probably they also should be set before a loop of legend creation like in __init__ or somewhere else. I did it because QGIS was crashing when layout and its legend is created.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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