2

Is there a way, using Python, to duplicate a layer in QGIS as many times as the single occurrences of a variable contained in a field and with a filter applied on the duplicated layer based on the variable itself?

An example: I have layer0 with a field0 that contains var1, var2, var3, etc. I would like the layer0 duplicated to layer1, layer2, layer3 etc. so that layer1 has a filter where field0 = var1, layer2 has a filter where field0 = var2, etc.

The idea is similar to the LayersByField plugin but instead of creating a new layer for each occurrence of a variable I wish to just duplicate the "master" layer (so to avoid unnecessary files on disk)

2
  • Just an FYI, I don't think the LayersByField plugin creates physical layers (i.e. they are not written to disk). As described in this post, the new layers are "virtual copies" which are saved within the project file (.qgs).
    – Joseph
    Dec 18, 2015 at 11:43
  • 1
    Joseph, you are right. The only issue I still have is that the plugin only works for shapefiles. I tried with ESRI FileGDB and Oracle Spatial but it produces wrong outputs. I am not sure if this is by design. Anyhow, as I said, it works as I need on shapefiles. Thanks
    – fabio2111
    Dec 18, 2015 at 14:24

2 Answers 2

4

The following Python script was tested with Shape files, PostGIS layers, and SpatiaLite using QGIS 2.8.2 on Windows 7. Specify the field you want to filter in the first code line (replace rtt).

# specify field to filter
field_name = 'rtt'

# get active layer
layer = iface.activeLayer()

# get reference to the field named above
fni = layer.fieldNameIndex(field_name)
f = layer.dataProvider().fields()

# get field type, necessary to build valid SQL string
is_string = False
if f[fni].type() in [7, 10]:
    is_string = True

# get list of unique values
unique_values = layer.uniqueValues(fni)
for i in unique_values:
    # add layer to the map
    lyr_copy = iface.addVectorLayer(layer.source(), layer.name() + '_' + str(i), layer.providerType())
    # build subset string in SQL like syntax
    if is_string:
        lyr_copy.setSubsetString('"%s" = \'%s\'' % (field_name, i))
    else:
        lyr_copy.setSubsetString('"%s" = %d' % (field_name, int(i)))

ESRI file Geodatabase didn't work for me since for all field indices layer.uniqueValues(fni) returns the list of unique values of the first attribute. Thus filtering of an attribut by these values returns an empty list or the wrong result set. Maybe an issue of QGIS 2.8.2.

2

I adapted @Detlev answer to transform it a processing script with some little tweaks :

##Dev_scripts=group
##Field_Filter=name

##input=vector
##field_name=field input

from qgis.core import QgsExpressionContextUtils
from qgis.utils import iface

layer = processing.getObject(input)
fields = layer.dataProvider().fields()
field_name_index = layer.fieldNameIndex(field_name)

# get field type, necessary to build valid SQL string
is_string = False
if fields[field_name_index].type() in [7, 10]:
    is_string = True

# get list of unique values
unique_values = layer.uniqueValues(field_name_index)
for i in unique_values:
    # add layer to the map
    lyr_copy = iface.addVectorLayer(layer.source(), layer.name() + '_' + str(i), layer.providerType())
    # build subset string in SQL like syntax
    if is_string:
        lyr_copy.setSubsetString('"%s" = \'%s\'' % (field_name, i))
    else:
        lyr_copy.setSubsetString('"%s" = %d' % (field_name, int(i)))
1
  • Would you mind updating that answer to the current QGIS 3 processing framework?
    – maxwhere
    Jan 27, 2020 at 16:31

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.