0

I have a shapefile that has 2 attributes named "X" and "Y". I want to change this to "Lon" and "Lat".

My (limited) experience tells me that I should read in the original shapefile, preserve the original driver, crs, make a new schema with "Lon" and "Lat" defined, and then write a new/new named shapefile.

Is there a quicker/easier way with fewer steps?

import fiona

with fiona.open(filein, 'r') as source:
    source_driver=source.driver
    source_crs=source.crs
    source_schema=source.schema
    print(source_schema)

new_schema= {'geometry': 'Point',
         'properties': { 'Lon': 'float:16.6', 
                         'Lat': 'float:16.6', 
                         'SP': 'float:16.6', 
                         'X_meter': 'float:19.11', 
                         'Y_meter': 'float:19.11', 
                         'Depth': 'float:19.8', 
                         'Line_Name': 'str:50', 
                         'SurveyID': 'str:50'}}

with fiona.open(fileout, 'w',
        driver=source_driver,
        crs=source_crs,
        schema=new_schema) as c:
    print(len(c))

c.closed
  • Is there a reason why you must code a solution to this for just one shapefile? You asked for a simpler way and that would be to use your GIS's attribute table GUI and in less time that it would take you to write and test your script, the job would be done. – MappaGnosis Jun 6 '14 at 7:00
  • The answer is two fold (1) Yes, I have to do this for multiple files- greater than 30, so a script would be nice and easy (2) I am committed to learning the ins and outs of Fiona. I could probably script this in ArcPy (I use ESRI) very quickly, but Fiona offers advantages of being independent of ESRI. – MfM Jun 9 '14 at 14:08
2

Fewer steps? No; Fiona reads and writes and by design doesn't support update in place. But you can eliminate a bunch of code using keyword args in fiona.open(). Find the positions of the X and Y fields in the schema by converting it to a pair of lists, update those lists, and zip them back together. That preserves the field order. Try this:

from collections import OrderedDict

import fiona


with fiona.open(filein, 'r') as source:

    old_schema_props = source.schema['properties']
    names, types = map(list, zip(*old_schema_props.items()))
    names[names.index('X')] = 'Lon'
    names[names.index('Y')] = 'Lat'
    new_schema_props = OrderedDict(zip(names, types))

    kwds = source.meta
    kwds['schema']['properties'] = new_schema_props

    with fiona.open(fileout, 'w', **kwds) as destination:

        for f in source:

            props = f['properties']
            names, values = map(list, zip(*props.items()))
            names[names.index('X')] = 'Lon'
            names[names.index('Y')] = 'Lat'
            f['properties'] = dict(zip(names, types))

            destination.write(f)
  • Thank you sgillies - very much appreciated! Learning concepts is usually pretty easy- but assembling them for efficiency? That takes more work. Thanks! – MfM Jun 9 '14 at 14:23

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.