PyQGIS – Adding Output Layers of QGIS Processing Scripts to Group

layertreepyqgisqgis-processing

I have a QGIS python processing scripts that return multiple rasters. I want to return them in a group named 'Aligned'. There is nothing in the context.addLayerToLoadOnCompletion() function to specify group.

I tried doing something like this to achieve what I want but it didn't work. It did create a group at the end of all layers in the layers panel, but the outputs were still added outside the group.

root = context.project().instance().layerTreeRoot()
group = root.addGroup('Aligned')
context.addLayerToLoadOnCompletion(
    outputs["Runoff Local"]["OUTPUT"],
    QgsProcessingContext.LayerDetails(
        f"Runoff Local (L) ", context.project(), "Runoff Local"
    ),
)

Is there a way to cleanly group all layers from the script in one group?

Best Answer

I was able to achieve this and this is my understanding:

If you do it through postProcessAlgorithm, QGIS will natively output layer as well, so you will have duplicate layers in your Canvas. So postProcessAlgorithm is not the best approach.

This is how I did it using the native QGIS output, rather than adding a layer to the canvas through my algorithm.

I first created a group through postProcessAlgorithm using Ben W's answer. This only creates and selects a group. Does not add anything.

    def postProcessAlgorithm(self, context, feedback):

        # following code make(if doesn't exist) and select a group so that the QGIS  spits layer at that location

        project = context.project()
        root = project.instance().layerTreeRoot()  # get base level node

        group = root.findGroup(self.run_name)  # find group in whole hierarchy
        if not group:  # if group does not already exists
            selected_nodes = (
                iface.layerTreeView().selectedNodes()
            )  # get all selected nodes
            if selected_nodes:  # if a node is selected
                # check the first node is group
                if isinstance(selected_nodes[0], QgsLayerTreeGroup):
                    # if it is add a group inside
                    group = selected_nodes[0].insertGroup(0, self.run_name)
                else:
                    parent = selected_nodes[0].parent()
                    # get current index so that new group can be inserted at that location
                    index = parent.children()(selected_nodes[0])
                    group = parent.insertGroup(index, self.run_name)
            else:
                group = root.insertGroup(0, self.run_name)

        # select the group
        select_group(self.run_name)

        return {}

Selection function made using the help of this Selecting subgroup in Layers panel using PyQGIS

def select_group(name: str) -> bool:
    """
    Select group item of a node tree
    """

    view = iface.layerTreeView()
    m = view.model()

    listIndexes = m.match(
        m.index(0, 0),
        Qt.DisplayRole,
        name,
        1,
        Qt.MatchFixedString | Qt.MatchRecursive | Qt.MatchCaseSensitive | Qt.MatchWrap,
    )

    if listIndexes:
        i = listIndexes[0]
        view.selectionModel().setCurrentIndex(i, QItemSelectionModel.ClearAndSelect)
        return True

    else:
        return False

Related Question