2

I am trying to get a layout to autogenerate as there is a certain set of information that I have to produce layouts for hundreds of times. I got the map, legend, and rest of the information to generate but the Legend is too large. It needs to only show the items in the map. I tried to do that manually but it still shows all the styles for each layer. Some of the layers used have 10+ styles so this is causing issues.

I was trying to use QgsLegendFilterButton as that is what I used when making a manual layout map but I can't seem to get that working in pyqgis. I have have been using guides to get the rest setup but couldn't find any on this so I'm totally lost at how to use QgsLegendFilterButton. Can anyone post a simple example of adding it to the code below? (if possible)

legend = QgsLayoutItemLegend(layout)
legend.setTitle("Legend")
layerTree = QgsLayerTree()
layerTree.addLayer(layer)
layers = QgsProject.instance().mapLayersByName('Cable')
layer = layers[0]
layerTree.addLayer(layer)
layers = QgsProject.instance().mapLayersByName('Attachment')
layer = layers[0]
layerTree.addLayer(layer)
legend.model().setRootGroup(layerTree)
newFont = QFont("Comic Sans MS", 6)
legend.setStyleFont(QgsLegendStyle.Title,newFont)
legend.setStyleFont(QgsLegendStyle.Subgroup, newFont)
legend.setStyleFont(QgsLegendStyle.SymbolLabel, newFont
layout.addLayoutItem(legend)
legend.attemptMove(QgsLayoutPoint(150,75, QgsUnitTypes.LayoutMillimeters))
4
  • 1
    uhm, interesting question. I only found this .cpp reference, which you might however find useful: github.com/nextgis/nextgisqgis/blob/master/src/app/… Nov 21, 2019 at 15:07
  • 1
    A different approach can be found here, at chapter 9.3: docs.qgis.org/3.4/pdf/en/… Nov 21, 2019 at 15:19
  • 1
    @RafDouglas It seems like that is for creating custom toolbar or hotkey buttons that use the functions. I tried some variations of this but nothing working yet. I'll keep at it.
    – Andrew
    Nov 21, 2019 at 15:25
  • 1
    @RafDouglas I tried what they had in chapter 9.3 but it seems the mapRenderer is no longer used. I found the new one docs.qgis.org/testing/pdf/en/… but it doesn't mention that line that looked promising using the mapRenderer legend.model().setLayerSet(mapRenderer.layerSet())
    – Andrew
    Nov 21, 2019 at 15:56

1 Answer 1

3

You need to use the method setLegendFilterByMapEnabled() and pass a Boolean value of True. However, the magic bullet is linking the legend item to a map item which is an instance of QgsLayoutItemMap. You haven't shown in your code block but I'm guessing you have already done something like:

map = QgsLayoutItemMap(layout)
layout.addItem(map)

...so you already have a QgsLayoutItemMap object.

In which case you can add the lines:

legend.setLinkedMap(map)
legend.setLegendFilterByMapEnabled(True)
legend.refresh()

Otherwise, if you are adding a legend to an existing layout, you could access the layout map items with something like this (depending upon how many map items you have in your layout):

map1 = [i for i in layout.items() if i.type()== 65639 and i.displayName() == 'Map 1'][0]    
map2 = [i for i in layout.items() if i.type()== 65639 and i.displayName() == 'Map 2'][0]

Also, if you link your legend and map and enable filter by map content, I think that creating a new LayerTree, adding layers to it and setting it as the legend model root group is redundant since your layout legend will only show the nodes which are visible in your layout map. If you do need to do this for some reason, a more efficient and probably more Pythonic way would be:

layer_names = ['Cable', 'Attachment']
layers = [i for i in QgsProject().instance().mapLayers().values() if i.name() in layer_names]
for l in layers:
    layerTree.addLayer(l)

Try the snippet below as a minimal example based on the code in your question:

legend = QgsLayoutItemLegend(layout)
legend.setTitle("Legend")
newFont = QFont("Comic Sans MS", 6)
legend.setStyleFont(QgsLegendStyle.Title,newFont)
legend.setStyleFont(QgsLegendStyle.Subgroup, newFont)
legend.setStyleFont(QgsLegendStyle.SymbolLabel, newFont)
layout.addLayoutItem(legend)
legend.attemptMove(QgsLayoutPoint(150,75, QgsUnitTypes.LayoutMillimeters))
legend.setLinkedMap(map) # pass a QgsLayoutItemMap object
legend.setLegendFilterByMapEnabled(True)
legend.refresh()
1
  • Everything worked great except I still had to declare layerTree = QgsLayerTree() I think that would be obvious for someone experienced but for someone who is new to QGIS and python it may not be.
    – Andrew
    Nov 25, 2019 at 14:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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