PyQGIS – Subsetting a Shapefile and Saving It

fields-attributespyqgispythonqgis

I am very new to PyQgis.

I have a shapefile containing a lot of information for each place, it looks like this

id    stat_1   stat_2 ... stat_n
i1     0        0          2
i2     1        1          0
            ...
iT     0        0          2

I want to create n shapefiles, containing for each of them: id and sta_i and only the locations which statistic is not equal to 0. Something like:

id    stat_i   
i3     1    
ij     2       
            ...
iT     4

Doing this manually would be quite tedious, which is why I decided to get started with PyQgis.
I figured out how to select my main layer and how to select the features I want ( I actually just figured out how to print them).
How can I actually create a new shapefile with the subsetted locations and just the two desired fields?
I will sort out how to loop over the fields later.

layer=None
fields=["id","stat_i"]

for lyr in QgsMapLayerRegistry.instance().mapLayers().values():
    if lyr.name() == "Layer_Name"
        layer = lyr
        break

request=QgsFeatureRequest().setFilterExpression(u'"stat_i"!=0')
it=layer.getFeatures(request)
for feat in it :
        print feat.id()

Best Answer

I guess there is an easier way to select your layer, subset your data and save it :

lyr = QgsMapLayerRegistry.instance().mapLayersByName("Layer_name")[0]
lyr.setSubsetString("stat_i != 0") # You can unset it by using None 
QgsVectorFileWriter.writeAsVectorFormat(lyr, "my_subset.shp",
                                        "UTF8", None, "ESRI Shapefile")

And so on with the n shapefiles you have to write.

Edit : I missed up the part where you want to select specific fields. I guess you can try (and improve!) something like this :

lyr = QgsMapLayerRegistry.instance().mapLayersByName("Layer_name")[0]
# Lets say you have 10 fields 'stat_x':
for i in range(10):
    lyr.setSubsetString("stat_{} != 0".format(i))
    fields = QgsFields() # It will contain your new fields (name and type)
    field1, field2 = 'id', 'stat_{}'.format(i)
    [fields.append(fi) for fi
     in (QgsField(field1, QVariant.Int),QgsField(field2, QVariant.Int))]

    # Here the args for QgsVectorFileWriter will be : 
    # FileName, Encoding, fields, GeometryType, CRS
    # See also http://qgis.org/api/classQgsVectorFileWriter.html
    writer_obj = QgsVectorFileWriter(
        "my_subset_n{}.shp".format(i), None, fields,
        lyr.dataProvider().geometryType(), lyr.crs())

    for ft in lyr.getFeatures():  # Loop on the subseted features
        # Create a new feature for each original feature
        new_ft = QgsFeature()
        # Give it its geometry :
        new_ft.setGeometry(ft.geometry())
        # Only keep the 2 selected fields :
        new_ft.setAttributes([ft[field1], ft[field2]])
        # Add the feature to the writer, ie. your output shapefile :
        writer_obj.addFeature(fet)

    del writer_obj # Features are written when the writer is deleted

If you haven't seen it, there is some useful insights in the pyQGIS doc about vector layers

Related Question