[GIS] Fiona error adding property to shapefile

fionapython

I'm getting the following error when trying to add a property to a .shp file using fiona in python:
Traceback (most recent call last):

  File "<ipython-input-38-5f04c3b56601>", line 17, in <module>
    j=j+1

  File "/Users/alex/anaconda/lib/python2.7/site-packages/fiona/collection.py", line 402, in __exit__
    self.close()

  File "/Users/alex/anaconda/lib/python2.7/site-packages/fiona/collection.py", line 386, in close
    self.flush()

  File "/Users/alex/anaconda/lib/python2.7/site-packages/fiona/collection.py", line 376, in flush
    self.session.sync(self)

  File "fiona/ogrext.pyx", line 939, in fiona.ogrext.WritingSession.sync (fiona/ogrext.c:15649)

RuntimeError: Failed to sync to disk

Here is my code – I'm adding a dummy property 'jazz' for now but I have many properties with both float and string types that I want to add once I figure out how to get it to work…

import random
#
import fiona

with fiona.open("data/subplace_maps/SP_SA_2011.shp") as input:
    schema2 = input.schema.copy()
    schema2['properties']['jazz'.decode('utf-8')] = 'str:50'
    temp = input.crs
    with fiona.open('data/subplace_maps/output.shp', 'w', crs=input.crs, driver=input.driver, schema=schema2) as sink:
        # iterate over shapefile shapes
        j = 0
        for elem in input:
            # update progress
            if(j % 500 == 0):
                print j,'/',len(input)
            #
            ja = ('jazz' + str(random.random())).decode('utf-8')
            elem['properties'].update(jazz=ja)
            #
            sink.write(elem)
            j=j+1

print 'done'

Best Answer

Fiona works with Python dictionaries (schema, features) and and more specifically Ordered Dictionaries

shape = fiona.open("a_shapefile.shp")
# schema of the shapefile
shape.schema
{'geometry': 'Point', 'properties': OrderedDict([(u'id', 'str:10')])}
# keys of the dictionary
shape.schema.keys()
['geometry', 'properties']
# first feature of the shapefile
elem = shape.next()
# keys of the dictionary
elem.keys()
['geometry', 'type', 'id', 'properties']
#  properties of the first feature
elem['properties']
OrderedDict([(u'id', u'1')])
#keys of the dictionary
elem['properties'].keys()
[u'id']
# value of the field/key 'id'
elem['properties']['id']
u'1'

When you modify the schema of your shapefile you simply add a new key:value to the dictionary

 schema2 = input.schema.copy() 
 # or
 schema2 = input.schema
 # add a new field to the dictionary (key:value)
 schema2['properties']['jazz'] = 'str:50' 
 print schema2
 {'geometry': 'Point', 'properties': OrderedDict([(u'id', 'int:10'), ...., (u'jazz', 'str:50')])}

And when you want to add/modify a value in the jazz field you simply add/modify the value of the key [jazz] (= elem['properties']['jazz'])

 with fiona.open('output.shp', 'w', crs=input.crs, driver=input.driver, schema=schema2) as sink:
    for elem in input:
        # elem is a dictionary with keys
        # original shapefile
        print "original: ", elem['properties']
        # now add the new value to the dictionary
        ja = ('jazz' + str(random.random()))
        elem['properties']['jazz'] = ja 
        print "modified: ", elem['properties']
        sink.write(elem)

original:  OrderedDict([(u'id', None)])
modified:  OrderedDict([(u'id', None),('jazz', 'jazz0.551109926166')])
....

Control (all is dictionaries)

test = fiona.open('output.shp')
elem = test.next()
elem
{'geometry': {'type': 'Point', 'coordinates': (0.21784342830509873, 0.37825773080975944)}, 'type': 'Feature', 'id': '0', 'properties': OrderedDict([(u'id', u'1'), (u'jazz', u'jazz0.551109926166')])}
elem['geometry']
{'type': 'Point', 'coordinates': (0.21784342830509873, 0.37825773080975944)}
elem['geometry']['coordinates']
(0.21784342830509873, 0.37825773080975944)
elem['properties']
OrderedDict([(u'id', u'1'), (u'jazz', u'jazz0.551109926166')])
elem['properties']['jazz']
u'jazz0.551109926166'
Related Question