4. Accessing the Table Of Contents (TOC)

Hint

The code snippets on this page need the following imports if you’re outside the pyqgis console:

from qgis.core import (
    QgsProject,
    QgsVectorLayer,
)

You can use different classes to access all the loaded layers in the TOC and use them to retrieve information:

  • QgsProject

  • QgsLayerTreeGroup

4.1. The QgsProject class

You can use QgsProject to retrieve information about the TOC and all the layers loaded.

You have to create an instance of QgsProject and use its methods to get the loaded layers.

The main method is mapLayers(). It will return a dictionary of the loaded layers:

layers = QgsProject.instance().mapLayers()
print(layers)
{'countries_89ae1b0f_f41b_4f42_bca4_caf55ddbe4b6': <QgsVectorLayer: 'countries' (ogr)>}

The dictionary keys are the unique layer ids while the values are the related objects.

It is now straightforward to obtain any other information about the layers:

1# list of layer names using list comprehension
2l = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
3# dictionary with key = layer name and value = layer object
4layers_list = {}
5for l in QgsProject.instance().mapLayers().values():
6  layers_list[l.name()] = l
7
8print(layers_list)
{'countries': <QgsVectorLayer: 'countries' (ogr)>}

You can also query the TOC using the name of the layer:

country_layer = QgsProject.instance().mapLayersByName("countries")[0]

Note

A list with all the matching layers is returned, so we index with [0] to get the first layer with this name.

4.2. QgsLayerTreeGroup class

The layer tree is a classical tree structure built of nodes. There are currently two types of nodes: group nodes (QgsLayerTreeGroup) and layer nodes (QgsLayerTreeLayer).

Note

for more information you can read these blog posts of Martin Dobias: Part 1 Part 2 Part 3

The project layer tree can be accessed easily with the method layerTreeRoot() of the QgsProject class:

root = QgsProject.instance().layerTreeRoot()

root is a group node and has children:

root.children()

A list of direct children is returned. Sub group children should be accessed from their own direct parent.

We can retrieve one of the children:

child0 = root.children()[0]
print(child0)
<QgsLayerTreeLayer: countries>

Layers can also be retrieved using their (unique) id:

ids = root.findLayerIds()
# access the first layer of the ids list
root.findLayer(ids[0])

And groups can also be searched using their names:

root.findGroup('Group Name')

QgsLayerTreeGroup has many other useful methods that can be used to obtain more information about the TOC:

# list of all the checked layers in the TOC
checked_layers = root.checkedLayers()
print(checked_layers)
[<QgsVectorLayer: 'countries' (ogr)>]

Now let’s add some layers to the project’s layer tree. There are two ways of doing that:

  1. Explicit addition using the addLayer() or insertLayer() functions:

    1# create a temporary layer
    2layer1 = QgsVectorLayer("path_to_layer", "Layer 1", "memory")
    3# add the layer to the legend, last position
    4root.addLayer(layer1)
    5# add the layer at given position
    6root.insertLayer(5, layer1)
    
  2. Implicit addition: since the project’s layer tree is connected to the layer registry it is enough to add a layer to the map layer registry:

    QgsProject.instance().addMapLayer(layer1)
    

You can switch between QgsVectorLayer and QgsLayerTreeLayer easily:

node_layer = root.findLayer(country_layer.id())
print("Layer node:", node_layer)
print("Map layer:", node_layer.layer())
Layer node: <QgsLayerTreeLayer: countries>
Map layer: <QgsVectorLayer: 'countries' (ogr)>

Groups can be added with the addGroup() method. In the example below, the former will add a group to the end of the TOC while for the latter you can add another group within an existing one:

node_group1 = root.addGroup('Simple Group')
# add a sub-group to Simple Group
node_subgroup1 = node_group1.addGroup("I'm a sub group")

To moving nodes and groups there are many useful methods.

Moving an existing node is done in three steps:

  1. cloning the existing node

  2. moving the cloned node to the desired position

  3. deleting the original node

1# clone the group
2cloned_group1 = node_group1.clone()
3# move the node (along with sub-groups and layers) to the top
4root.insertChildNode(0, cloned_group1)
5# remove the original node
6root.removeChildNode(node_group1)

It is a little bit more complicated to move a layer around in the legend:

 1# get a QgsVectorLayer
 2vl = QgsProject.instance().mapLayersByName("countries")[0]
 3# create a QgsLayerTreeLayer object from vl by its id
 4myvl = root.findLayer(vl.id())
 5# clone the myvl QgsLayerTreeLayer object
 6myvlclone = myvl.clone()
 7# get the parent. If None (layer is not in group) returns ''
 8parent = myvl.parent()
 9# move the cloned layer to the top (0)
10parent.insertChildNode(0, myvlclone)
11# remove the original myvl
12root.removeChildNode(myvl)

or moving it to an existing group:

 1# get a QgsVectorLayer
 2vl = QgsProject.instance().mapLayersByName("countries")[0]
 3# create a QgsLayerTreeLayer object from vl by its id
 4myvl = root.findLayer(vl.id())
 5# clone the myvl QgsLayerTreeLayer object
 6myvlclone = myvl.clone()
 7# create a new group
 8group1 = root.addGroup("Group1")
 9# get the parent. If None (layer is not in group) returns ''
10parent = myvl.parent()
11# move the cloned layer to the top (0)
12group1.insertChildNode(0, myvlclone)
13# remove the QgsLayerTreeLayer from its parent
14parent.removeChildNode(myvl)

Some other methods that can be used to modify the groups and layers:

 1node_group1 = root.findGroup("Group1")
 2# change the name of the group
 3node_group1.setName("Group X")
 4node_layer2 = root.findLayer(country_layer.id())
 5# change the name of the layer
 6node_layer2.setName("Layer X")
 7# change the visibility of a layer
 8node_group1.setItemVisibilityChecked(True)
 9node_layer2.setItemVisibilityChecked(False)
10# expand/collapse the group view
11node_group1.setExpanded(True)
12node_group1.setExpanded(False)