Buffering Point Shapefile Using GDAL/OGR: Copying Input Attributes to Output Shapefile

bufferogrpyshppythonshapely

Editing my previous question which asked the best way to buffer a point shapefile in python to add more detail and clarity to what I'm looking for.

I have found a method here to iterate through an input point feature class, buffer by a distance and write to an output polygon feature class:

def create_bufferShp_fromPointShp(inShpPath, bufferSize):

    buffShpPath = inShpPath.replace('.shp', '_buffer-{}m.shp'.format(bufferSize))

    inputds = ogr.Open(inShpPath)
    inputlyr = inputds.GetLayer()

    shpdriver = ogr.GetDriverByName('ESRI Shapefile')
    if os.path.exists(buffShpPath):
        shpdriver.DeleteDataSource(buffShpPath)
    outputBufferds = shpdriver.CreateDataSource(buffShpPath)
    bufferlyr = outputBufferds.CreateLayer(buffShpPath, geom_type=ogr.wkbPolygon)
    featureDefn = bufferlyr.GetLayerDefn()

    for feature in inputlyr:
        ingeom = feature.GetGeometryRef()
        geomBuffer = ingeom.Buffer(bufferSize)

        outFeature = ogr.Feature(featureDefn)
        outFeature.SetGeometry(geomBuffer)
        bufferlyr.CreateFeature(outFeature)
        outFeature = None

    # Copy the input .prj file
    from shutil import copyfile
    copyfile(inShpPath.replace('.shp', '.prj'), buffShpPath.replace('.shp', '.prj'))

    return buffShpPath

The resulting polygon feature class is exactly what I'm looking for, but I would like to carry over the attributes from the input feature class to the output. These fields may change, so I am looking for an automated way. I added this portion to before the for loop:

    # Try to create new fields in the output shp
    for i in range(inputlyr.GetLayerDefn().GetFieldCount()):
        bufferlyr.CreateField(inputlyr.GetLayerDefn().GetFieldDefn(i))

This creates the fields, but I am unsure (outside of hardcoding the fields with outFeature.SetField()) of the best way to copy the input attributes of a feature to the output feature class.

Best Answer

This worked for me:

def create_bufferShp_fromPointShp(inShpPath, bufferSize):

    buffShpPath = inShpPath.replace('.shp', '_buffer-{}m.shp'.format(bufferSize))

    print "\nCreating buffered shapefile..."

    inputds = ogr.Open(inShpPath)
    inputlyr = inputds.GetLayer()

    shpdriver = ogr.GetDriverByName('ESRI Shapefile')
    if os.path.exists(buffShpPath):
        shpdriver.DeleteDataSource(buffShpPath)
    outputBufferds = shpdriver.CreateDataSource(buffShpPath)
    bufferlyr = outputBufferds.CreateLayer(buffShpPath, geom_type=ogr.wkbPolygon)
    featureDefn = bufferlyr.GetLayerDefn()

    # Create new fields in the output shp and get a list of field names for feature creation
    fieldNames = []
    for i in range(inputlyr.GetLayerDefn().GetFieldCount()):
        fieldDefn = inputlyr.GetLayerDefn().GetFieldDefn(i)
        bufferlyr.CreateField(fieldDefn)
        fieldNames.append(fieldDefn.name)

    for feature in inputlyr:
        ingeom = feature.GetGeometryRef()
        fieldVals = [] # make list of field values for feature
        for f in fieldNames: fieldVals.append(feature.GetField(f))

        outFeature = ogr.Feature(featureDefn)
        geomBuffer = ingeom.Buffer(bufferSize)
        outFeature.SetGeometry(geomBuffer)
        for v, val in enumerate(fieldVals): # Set output feature attributes
            outFeature.SetField(fieldNames[v], val)
        bufferlyr.CreateFeature(outFeature)

        outFeature = None

    # Copy the input .prj file
    from shutil import copyfile
    copyfile(inShpPath.replace('.shp', '.prj'), buffShpPath.replace('.shp', '.prj'))


    return buffShpPath
Related Question