8

I wrote the script to copy a existing shapefile tc_line to a new file tc_pi, and it ran fine:

from shapely.geometry import mapping, shape
import fiona

with fiona.open('tc_line.shp', 'r') as input:
    schema = input.schema.copy()
    input_crs = input.crs
    with fiona.open('tc_pi.shp', 'w', 'ESRI Shapefile', schema, input_crs) as output:
        for elem in input:
            output.write({'properties':elem['properties'],'geometry': mapping(shape(elem['geometry']))})

Now I want to copy the existing file and add a new column (type: float) containing "1" to the attribute table (I would like the new-added column to be attached to the right of the existing columns in the attribute talle), so I edited the code above to this:

from shapely.geometry import mapping, shape
import fiona

with fiona.open('tc_line.shp', 'r') as input:
    schema = input.schema.copy()
    input_crs = input.crs
    schema['properties']['pi'] = 'float'
    with fiona.open('tc_pi.shp', 'w', 'ESRI Shapefile', schema, input_crs) as output:
        for elem in input:
            output.write({'properties':elem['properties'],'geometry': mapping(shape(elem['geometry']))})

but error occurred:

Traceback (most recent call last):


File "C:\Users\Heinz\Desktop\test.py", line 10, in <module>
    output.write({'properties':elem['properties'],'geometry': mapping(shape(elem['geometry']))})
  File "C:\Python27\lib\site-packages\fiona\collection.py", line 333, in write
    self.writerecords([record])
  File "C:\Python27\lib\site-packages\fiona\collection.py", line 327, in writerecords
    self.session.writerecs(records, self)
  File "fiona/ogrext.pyx", line 1024, in fiona.ogrext.WritingSession.writerecs (fiona/ogrext.c:17361)
ValueError: Record does not match collection schema: [u'cat_', u'value', u'label'] != ['pi', u'label', u'value', u'cat_']

How to solve this and achieve my objective of 'copy the existing file and add a new column (type: float) containing "1" to the attribute table of new file'?

I am working with python 2.7.12, Fiona 1.7.0

PolyGeo
  • 65,136
  • 29
  • 109
  • 338
Heinz
  • 1,545
  • 5
  • 26
  • 42

1 Answers1

10

It seems to me that you have some problems with Fiona. Remember that all the elements are dictionaries

1) you define a new field schema['properties']['pi'] = 'float'
2) this field must be in in the properties of every elements

with fiona.open('tc_line.shp', 'r') as input:
    schema = input.schema.copy()
    input_crs = input.crs
    schema['properties']['pi'] = 'float'
    with fiona.open('tc_pi.shp', 'w', 'ESRI Shapefile', schema, input_crs) as output:
         for elem in input:
              elem['properties']['pi']= 1
              output.write({'properties':elem['properties'],'geometry': mapping(shape(elem['geometry']))})

If you're not comfortable with Python dictionaries, use GeoPandas (it uses Fiona)

import geopandas as gpd
gdf = gpd.read_file("tc_line.shp")
gdf["pi"]= 1
gdf.to_file("tc_pi.shp") 
gene
  • 54,868
  • 3
  • 110
  • 187
  • Thank you for the answer, since I edited my post earlier, should I post other parts (without add column issue) of the question in a new post? – Heinz Oct 30 '16 at 13:46
  • 1
    I think, yes, because the answer is for 1) – gene Oct 30 '16 at 14:19
  • Thanks for the comment, I have posted another post: http://gis.stackexchange.com/questions/215982/python-how-to-find-out-and-edit-specific-rows-of-attribute-table-in-a-line-shap – Heinz Oct 30 '16 at 15:00