[GIS] How to duplicate a map layer at most once as the bottom layer in qgis3 (python)

pyqgisqgis-3table of contents

I wanted to duplicate a layer in qgis3 using python (display the same vector data as different layers) per this question (How can I duplicate a layer in QGIS?). In addition, I need to:

  1. make sure that the added clone layer is at the bottom of the layers

  2. check if the clone already exists and duplicate only if the clone doesn't exist among the current list of layers (to avoid multiple clones).

The code I have so far (for duplicating the first layer) is:

vl = iface.mapCanvas().layer(0)
vl_clone = iface.addVectorLayer(vl.source(), vl.name() + "_clone", vl.providerType())

Currently the new layer is added to the top and becomes layer(0). I tried to follow existing GIS.SE questions (e.g. How to move layers in the Layer Order Panel using PyQGIS?). But existing questions/answers are for QGIS 2, and involve breaking changes in QGIS3 (e.g. iface.layerTreeCanvasBridge())

Does anyone know how to extend the above code to work in QGIS3?

— EDIT —

The current code I have so far from synthesizing existing answers/documentation is below. Still, the layer order doesn't change. I tried different values in insert() such as 3, to no avail.

lyr1 = iface.mapCanvas().layer(0)
lyr1_clone = iface.addVectorLayer(lyr1.source(), lyr1.name() + "_clone", lyr1.providerType())

bridge = iface.layerTreeCanvasBridge()
treeRoot = QgsProject.instance().layerTreeRoot()
treeRoot.setHasCustomLayerOrder(True)
order = treeRoot.customLayerOrder() 
order.insert( -1 , order.pop() ) # lyr1_clone to the bottom # lyr1_clone to the bottom
treeRoot.setCustomLayerOrder( order )
bridge.setCanvasLayers()

Best Answer

If you want to add a duplicated layer at the bottom (in both the Layers Panel and the Layer Order Panel), you could use:

lyr1 = iface.mapCanvas().layer(0)
lyr1_clone = QgsVectorLayer(lyr1.source(), lyr1.name() + "_clone", lyr1.providerType())
QgsProject.instance().addMapLayer(lyr1_clone, False)

treeRoot = QgsProject.instance().layerTreeRoot()
treeRoot.insertChildNode(-1, QgsLayerTreeLayer(lyr1_clone))

If you want to check if your duplicated layer already exists (by name) then you could use:

treeRoot = QgsProject.instance().layerTreeRoot()

lyr1 = iface.mapCanvas().layer(0)
lyr1_clone = QgsVectorLayer(lyr1.source(), lyr1.name() + "_clone", lyr1.providerType())

layer_names = [layer.name() for layer in QgsProject.instance().mapLayers().values()]
if lyr1_clone.name() not in layer_names:
    QgsProject.instance().addMapLayer(lyr1_clone, False)
    treeRoot.insertChildNode(-1, QgsLayerTreeLayer(lyr1_clone))
else:
    del lyr1_clone