2

I need to create a layer tree for other user researchers to use. In the final dataset there will be ~20 sub-groups, each with dozens of layers. (It's possible that this isn't the best way to do it -- the reason for so many layers is to have individually-selectable lines, where the end user can hide all layers but one.)

I want to export the top level group in a way that:

  • preserves the organization of layers into sub-groups and the top-level group
  • includes the symbology
  • is compatible with being loaded into existing QGIS projects.

What I’ve tried so far:

  • Programmatically saving a layer: I can use QgsVectorFileWriter.writeAsVectorFormat to save a single layer, but I haven’t figured out how to get multiple layers into the same file or to save the layer groups.
  • Using the Processing Toolbox’s Database -> Package layers function. This makes it straightforward to export as many layers as desired, but I can’t figure out how to preserve the hierarchy.
  • [23 Nov update] Right-click on top level group -> Export -> Save as Layer Definition File. This saves the hierarchy, but when imported, none of the layers have any data. If instead I use layers with a CSV as the provider, this kind of works, but the data isn't packaged with the exported file -- instead it is a relative path on my computer, which isn't good for distribution.

Is there a way to do this?

I'm using QGIS 3.22 on a Mac.


23 Nov Update:

Here's a screenshot of my demo QGIS project; I'm trying to export the tree rooted at "Project Index": QGIS screencap

And the code used to generate that layer tree:

import random

root = QgsProject.instance().layerTreeRoot()
top_level_group = root.insertGroup(0, "Project Index")  # Inserts at specified index

institutions = {1: ['A', 'B', 'C'], 2: ['D', 'E'], 3: ['F']}

for institution, projects in institutions.items():
    institution_group = top_level_group.addGroup("Institution {}".format(institution))
    for project in projects:
        project_group = institution_group.addGroup("Project {}".format(project))
        # Add a point layer containing a single point
        pt_x = random.randint(-10000, 10000)  # 20km wide box about origin
        pt_y = random.randint(-10000, 10000)
        pt_uri = "point?crs=epsg:3031"
        pt_layer = QgsVectorLayer(pt_uri, "Point", "memory")
        pt_feature = QgsFeature()
        pt_feature.setGeometry(QgsGeometry.fromPointXY(QgsPointXY(pt_x, pt_y)))
        pt_prov = pt_layer.dataProvider()
        pt_prov.addFeature(pt_feature)
        pt_layer.updateExtents()
        QgsProject.instance().addMapLayer(pt_layer, False) 
        project_group.addLayer(pt_layer)
        
        # Add a polygon layer containing a 5km square
        poly_x0 = random.randint(-10000, 10000)
        poly_y0 = random.randint(-10000, 10000)
        vertices = [(poly_x0, poly_y0), (poly_x0, poly_y0 + 5000),
                    (poly_x0+5000, poly_y0+5000), (poly_x0+5000, poly_y0)]
        poly_points = [QgsPointXY(xx, yy) for xx,yy in vertices]
        poly_uri = "polygon?crs=epsg:3031"
        poly_layer = QgsVectorLayer(poly_uri, "Polygon", "memory")
        poly_feature = QgsFeature()
        poly_feature.setGeometry(QgsGeometry.fromPolygonXY([poly_points]))
        poly_prov = poly_layer.dataProvider()
        poly_prov.addFeature(poly_feature)
        poly_layer.updateExtents()
        QgsProject.instance().addMapLayer(poly_layer, False) 
        project_group.addLayer(poly_layer)
        
        # Add a polyline layer
        npts = random.randint(5,10)
        line_points = []
        for _ in range(npts):
            xx = random.randint(-10000, 10000)
            yy = random.randint(-10000, 10000)
            line_points.append(QgsPoint(xx, yy))
        print(line_points)
        line_uri = "linestring?crs=epsg:3031"
        line_layer = QgsVectorLayer(line_uri, "LineString", "memory")
        line_feature = QgsFeature()
        line_feature.setGeometry(QgsGeometry.fromPolyline(line_points))
        line_prov = line_layer.dataProvider()
        line_prov.addFeature(line_feature)
        line_layer.updateExtents()
        QgsProject.instance().addMapLayer(line_layer, False) 
        project_group.addLayer(line_layer)
7
  • Can you please show how visually do they look like ?
    – Taras
    Commented Nov 22, 2022 at 7:47
  • Are you just wanting to programmatically replicate the 'Export > Save as Layer Definition File', at the group level?
    – nr_aus
    Commented Nov 22, 2022 at 7:51
  • @nr_aus - That's close, but doesn't seem to do what I need. The resulting qlr file appears to have the correct group hierarchy, but doesn't seem to have the actual data in it. (The layers were originally created with points in memory, not from a file.)
    – user670416
    Commented Nov 23, 2022 at 1:26
  • @Taras -- Thanks for cleaning up the post! And, I've added a screencap.
    – user670416
    Commented Nov 23, 2022 at 21:18
  • Will you be creating your layers programatically as in your demo file, or is that just an example?
    – Llaves
    Commented Nov 24, 2022 at 16:59

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.