I've got a script which adds a legend to a print layout. It works perfectly as a script but when I try to implement this in the processAlgorithm of a QGIS plugin, it doesn't work.
If it is helpful, the full code for the plugin is here: https://github.com/epurpur/eco-valuator/blob/CreateAndExportPrintLayout/create_print_layout_and_export_map.py
I'm pretty sure the problem is with the following line:
legend.model().setRootGroup(root)
Here is my script (outside the plugin):
"""This creates a new print layout"""
project = QgsProject.instance()
manager = project.layoutManager()
layout = QgsPrintLayout(project)
layoutName = "PrintLayout"
layout = QgsPrintLayout(project)
layout.initializeDefaults()
layout.setName(layoutName)
manager.addLayout(layout)
"""Gathers active layers to add to legend"""
checked_layers = [layer.name() for layer in QgsProject().instance().layerTreeRoot().children() if layer.isVisible()]
layersToAdd = [layer for layer in QgsProject().instance().mapLayers().values() if layer.name() in checked_layers]
root = QgsLayerTree()
for layer in layersToAdd:
print(f"Adding {layer.name()} to legend")
root.addLayer(layer)
"""This adds a legend item to the Print Layout"""
legend = QgsLayoutItemLegend(layout)
legend.model().setRootGroup(root)
layout.addLayoutItem(legend)
legend.attemptMove(QgsLayoutPoint(246, 5, QgsUnitTypes.LayoutMillimeters))
This adds a nice legend, with just the active layers:
When implemented in the processAlgorithm of my plugin, I either get a map with no legend or QGIS crashes. So something is broken. To help troubleshoot, I added a print statement in my for loop when adding layers to my "root" object, and this works correctly. The next time I interact with "root" is in this line (as stated above):
legend.model().setRootGroup(root)
To spare you another long code block, my processAlgorithm is EXACTLY the same code except it is all nested within this:
def processAlgorithm(self, parameters, context, feedback):
"""This actually does the processing for creating the print layout and exporting as .pdf"""
log = feedback.setProgressText
rest of code exactly as it was above
If I comment out all lines related to gathering just the active layers:
between """Gather active layers...""" and root.addLayer(layer), and the line: legend.model().setRootGroup(root)
and then run my plugin, I get a legend (except it adds all layers and looks bad):
I asked a similar question on StackOverflow recently as I was having trouble with adding a map item to my print layout and Nyall Dawson was nice enough to provide me this function to include in my code:
def flags(self):
return super().flags() | QgsProcessingAlgorithm.FlagNoThreading
and it worked! I was able to add a map object. But to be honest I don't know what this does, or if this issue is related.