4

I've tried to use fiona and shapely and ogr, but the tutorials seem to be insufficient to describe how to do such a seemingly simple task. In arcpy this could be done simply with an update cursor. I'm trying to use open source tools here but I'm having some difficulty with editing the attribute table. I'm not interested in creating a new shapefile.

Any suggestions?

(Edit) For example how can I implement the following code using open source tools?

cursor = arcpy.da.UpdateCursor(shpfilepath, ["OID@", "Elevation"]) 
for row in cursor:
    row[1] = 15 
    cursor.updateRow(row) 
del cursor

This would change the values of the "Elevation" attribute of all features of shpfilepath to be 15.

(Edit 2) I'm trying to run this as an external script, not as part of QGIS. (Edit 3) I ended up doing it like this:

def addfields(shapefilename, fieldNames):                                             
    #adds fields and values to shapefile                                                     
    #using fieldName, a dictionary that has the structure:
    #["ColumnName":"Value"]         

    #filehandling to open layer                                                       
    shape = shapefilename                                                             
    driver = ogr.GetDriverByName('ESRI Shapefile')                                    
    dataSource = driver.Open(shape, 1) #1 is read/write                               
    layer = dataSource.GetLayer()                                                     

    #add fieldnames using ogr                                                         
    for field in fieldNames:                                                          
        fldDef1 = ogr.FieldDefn(field, ogr.OFTString)                                 
        fldDef1.SetWidth(16) #16 char string width                                    
        layer.CreateField(fldDef1)                                                    


    #iterate through features using fid and add values with ogr                       
    for fieldName in fieldNames:                                                      
        for fid in range(layer.GetFeatureCount()):                                    
            feature = layer.GetFeature(fid)                                           
            feature.SetField(fieldName, fieldNames[fieldName])                        
            layer.SetFeature(feature)                                                 

3 Answers 3

4

I tend to use the following standalone script which uses PyQGIS to update fields in a shapefile (remember to set your PATHS correctly, I followed @gcarrillo's answer and using Windows 7):

import os, sys
from qgis.core import *
from qgis.gui import *
from PyQt4.QtGui import *

# Set environment
QgsApplication( [], False, home + "/AppData/Local/Temp" )
QgsApplication.setPrefixPath("C://OSGeo4W64//apps//qgis", True)
QgsApplication.initQgis()
app = QApplication([])

layer = QgsVectorLayer("/path/to/shapefile", "name", "ogr")

idx = layer.fieldNameIndex('Elevation')
layer.startEditing()
for feat in layer.getFeatures():
    layer.changeAttributeValue(feat.id(), idx, 15)

layer.commitChanges()

QgsApplication.exitQgis()
app.exit()
4
  • I'm trying to use your script but I get the following error: with edit(layer): NameError: name 'edit' is not defined
    – Jas
    Mar 8, 2016 at 0:34
  • I forgot to add your name so you'd see it, so I did that here.
    – Jas
    Mar 8, 2016 at 7:48
  • @Jas - No problem! Thanks for mentioning the error, edited the code.
    – Joseph
    Mar 8, 2016 at 10:07
  • I have the same problem - did you get an answer for this? Jan 24, 2020 at 15:44
3

Fiona use dictionaries therefore with your example

for feature in fiona.open(a shapefile): # = for row in cursor:
    feature['properties']['Elevation']= 15 # = row[1] = 15 

And no need to update a cursor because feature is a dictionary

Now, if you want to update the layer, and not the dictionary, Fiona does not like very much to modify an open shapefile (as ogr). It is preferable to make a copy

with fiona.open(ashapefile) as input:
   # schema and crs of the the new shapefile = those of input shapefile
   schema = input.schema
   crs = input.crs
   # creation of the new shapefile
   with fiona.open('copy.shp', 'w',schema=schema, crs=crs) as output:
       for features in input:
          geom = input['geometry']
          prop = input['properties']
          # change value of the row
          prop['properties']['Elevation']= 15
          output.write({'geometry':geom, 'properties': prop})
1
  • 1
    Thanks! This is great. I especially like that you took the time to explain a bit about the feature being a dictionary. It's comments like yours that help me to understand the framework being presented in a more comprehensive way.
    – Jas
    Mar 13, 2016 at 9:11
2

You can do that in QGIS without shapely or fiona. For example, next code it is equivalent to yours:

layer = iface.activeLayer()

provider = layer.dataProvider()

feats = [ feat for feat in layer.getFeatures() ]

n = len(feats)

for i in range(n):
    new_values = { 1 : 15 } #row 1, value 15
    provider.changeAttributeValues( {i:new_values} )

This would change the values of the attribute in row 1, of all features of active layer, to be 15. I tried out the code with the shapefile of next image and it worked; as it can be observed at the attributes table (row 1 is values field).

enter image description here

2
  • Thanks for your simple explanation and example. I'm sure this will be helpful. Perhaps you have a similarly simple solution for my other question. gis.stackexchange.com/questions/183606/…
    – Jas
    Mar 6, 2016 at 11:47
  • I'm tempted to accept the answer as I did not explicitly specify in my original question that I'm trying to run this as an external script. Is it possible to modify the code that you presented to run externally?
    – Jas
    Mar 6, 2016 at 22:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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