pyQGIS Efficiently modify all the features in a layer

The command to apply changes to layers has a substantial overhead so the key to modifying layers efficiently is to build a dictionary of modifications and apply them using one single command. This example function takes a layer as an input and returns a new layer in memory containing a copy of allthe origianl feature with two new attributes.

I use this function as a template for all the modifications I make across whole layers. I just insert the code for modifying the geometry or attributes of the copied featrues at teh appropriate points. The code is fairly heavily tested and working.

import os
def layer_mod(input_layer):
  from PyQt4.QtCore import *
  my_WkbType = { 'WKBUnknown': 0, 'WKBPoint':1, 'WKBLineString':2, 'WKBPolygon':3, 'WKBMultiPoint':4, 'WKBMultiLineString':5, 'WKBMultiPolygon':6, 'WKBNoGeometry':7, 'WKBPoint25D':8, 'WKBLineString25D':9, 'WKBPolygon25D':10, 'WKBMultiPoint25D':11, 'WKBMultiLineString25D':12, 'WKBMultiPolygon25D':13 }
  my_rev_WkbType = {v:k for k, v in my_WkbType.items()}
  QGisWKBType=input_layer.dataProvider().geometryType()
  EPSG_code=int(input_layer.dataProvider().crs().authid().split(":")[1])
  destination_layer=QgsVectorLayer(my_rev_WkbType[QGisWKBType][3:]+'?crs=epsg:'+str(EPSG_code)+'&index=yes','memory layer','memory')
  QgsMapLayerRegistry.instance().addMapLayer(destination_layer)
  if not destination_layer.isValid():
    print "Failed to create memory layer"
    raise
  #Add input_layer attribute fields
  input_layer_attrib_names = input_layer.dataProvider().fields()
  oldattributeList = input_layer.dataProvider().fields().toList()
  newattributeList=[]
  for attrib in oldattributeList:
    if destination_layer.fieldNameIndex(attrib.name())==-1:
      newattributeList.append(QgsField(attrib.name(),attrib.type()))
  destination_layer.dataProvider().addAttributes(newattributeList)
  destination_layer.updateFields()
  #Add additional attribute fields
  New_fields_list=[]
  New_fields_list.append(QgsField("mytextfield", QVariant.String))
  New_fields_list.append(QgsField("myintfield", QVariant.Int))
  destination_layer.dataProvider().addAttributes(New_fields_list)
  destination_layer.updateFields()
  destination_layer_attribute_list=destination_layer.dataProvider().fields().toList()
  #Copy features over to the the new memory layer
  destination_layer.startEditing()
  cfeatures=[]
  xfeatures = input_layer.getFeatures()
  for xfeature in xfeatures:
    #Create destination feature
    cfeature = QgsFeature()
    #Populate feature with geometry
    xgeometry = xfeature.geometry()
    cfeature.setGeometry(xgeometry)
    #Populate feature with attributes
    cfeature_Attributes=[]
    for destination_QGSfield in destination_layer_attribute_list:
      attribute_field=destination_QGSfield.name()
      attr_still_to_append=True
      #Get old attribute value and append
      idx = input_layer.fieldNameIndex(attribute_field)
      if idx>=0:
        cfeature_Attributes.append(xfeature.attributes()[idx])
        attr_still_to_append=False
      #overwrite with mods here
      if attribute_field == "mytextfield":
        cfeature_Attributes.append("add text here")
        attr_still_to_append=False
      if attribute_field == "myintfield":
        cfeature_Attributes.append(42)
        attr_still_to_append=False
      #Append a Null into any unfound attributes
      if attr_still_to_append:
        cfeature_Attributes.append(None)
    cfeature.setAttributes(cfeature_Attributes)
    cfeatures.append(cfeature)
  destination_layer.dataProvider().addFeatures(cfeatures)
  destination_layer.commitChanges()
  destination_layer.updateExtents()
  return destination_layer

Leave a Reply

Your email address will not be published. Required fields are marked *


9 × = eighty one