26

I have a Python script that adds an attribute field to a Shapefile if doesn't exist. This is easy to do with ArcGIS (graphically or via Python), but I'm looking for something that doesn't depend on ArcGIS.

I tried this unsuccessfully with OGR, since my Shapefile contains features.

I've looked at pyshp, but similarly there is no way to modify the schema after it has been created. I haven't had a try with shapefile (for Python), but I don't see this feature advertised. I also can't see how this can be done by tinkering with the DBF file via dbfpy.

Does anyone have any ideas?

4

5 Answers 5

9

you should have a look on these questions since it has been answered already : How to add custom Feature attributes to Shapefile using Python?

https://stackoverflow.com/questions/4215658/adding-custom-feature-attributes-to-esri-shapefile-with-python

If you want as result, only one shapefile, just delete your input files at the end of your script.

1
4

Thanks to a rather brain-dead format called DBF, adding fields to shapefiles with existing attribute data isn't possible without rewriting or adding padding to the DBF. I don't know of a ready-made solution, but what I would do is write a script to create a new shapefile based on an existing one and add the extra field(s) to the new shapefile. Then copy the geometry/attribute data from old to new shapefile. And as a final step, remove the old shapefile, and rename the new one. All of this is fairly easily accomplished using OGR python bindings.

Alternately, you can use dbfpy to do the above with just the DBF file. Order of steps remains the same:

  1. Create a new DBF with identical structure to original
  2. Create new attribute fields in the new DBF
  3. Copy data from original DBF to new DBF
  4. Remove old DBF, rename new DBF to old DBF

You don't need to make any changes to the shapefile (.shp) itself or any of the other files, as they do not reference attribute information contained in the DBF. You do however need to keep the order of records exactly the same in the old and the new DBF.

4

Here's a solution. Better late than never:

http://geospatialpython.com/2013/04/add-field-to-existing-shapefile.html?m=1

3

DBFpy should work for this. Have you seen then example on this page:

http://dbfpy.sourceforge.net/

Make sure the shapefile isn't being edited by any other application including ArcGIS at the time as this may cause issues via locking.

5
  • I don't think this works if you already have data in the DBF file. I had looked at it before, but I get an error: "At least one record was added, structure can't be changed". Do you have any specific example in mind?
    – Mike T
    Mar 18, 2011 at 11:18
  • Ah I remember now yes as Sasa said the creation of a new DBF would be required. Copy the schema (as in fields etc.) across then make your additions, then copy the records across. The "great" DBF... :(
    – Rob Clark
    Mar 18, 2011 at 13:46
  • @Mike How was a record added when all you want to do is add a field?? Adding a record is an error because it ruins the connection between the attributes and the shapes. Adding a field does no harm at all. Any library that can edit dbf files will do the job properly.
    – whuber
    Mar 18, 2011 at 15:23
  • @whuber: That is their error message. Open an existing dbf that has data and see: from dbfpy import dbf; db = dbf.Dbf('my.dbf'); db.addField(("FOO", "C", 15))
    – Mike T
    Mar 18, 2011 at 21:52
  • @Mike Thanks for clarifying the situation. That sounds like the result of an unnecessary limitation in dbfpy :-(. I can guess why: adding a field in a non-empty database requires all the records to be physically read, expanded, and written back out again. A good solution is to find a different dBase library or use other software ;-).
    – whuber
    Mar 18, 2011 at 22:08
3

I found a solution using OGR and thanks to help from a previous question. Here is a complete example:

from osgeo import ogr

# Open a Shapefile, and get field names
source = ogr.Open('my.shp', update=True)
layer = source.GetLayer()
layer_defn = layer.GetLayerDefn()
field_names = [layer_defn.GetFieldDefn(i).GetName() for i in range(layer_defn.GetFieldCount())]
print(len(field_names))
print('MYFLD' in field_names)

# Add a new field
new_field = ogr.FieldDefn('MYFLD', ogr.OFTInteger)
layer.CreateField(new_field)

# Close the Shapefile
source = None

My problem was that I used layer_defn.AddFieldDefn(new_field) rather than layer.CreateField(new_field). Many thanks to the help, and sorry for not throughly checking for the similar other question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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