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)

user670416
  • 143
  • 3
  • Can you please show how visually do they look like ? – Taras Nov 22 '22 at 07:47
  • Are you just wanting to programmatically replicate the 'Export > Save as Layer Definition File', at the group level? – nr_aus Nov 22 '22 at 07: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 Nov 23 '22 at 01:26
  • @Taras -- Thanks for cleaning up the post! And, I've added a screencap. – user670416 Nov 23 '22 at 21:18
  • Will you be creating your layers programatically as in your demo file, or is that just an example? – Llaves Nov 24 '22 at 16:59
  • If the goal is just showing single lines/features from a layer, rather than creating a new layer for each feature, consider the methods in this post – Llaves Nov 24 '22 at 17:03
  • @Llaves -- yes, I will be creating my layers programmatically. And instead of having a single point/polygon/line, they'll each have thousands of points. I expect users to need to toggle them on/off pretty regularly, and to want to toggle on/of both individual layers and layer groups. I don't see how to apply the rule-based symbology in this case. – user670416 Nov 24 '22 at 22:32

0 Answers0