Jump to content

Multiple buffer with arcpy ArcGIS


Recommended Posts

Hi all,

I need some help with python code and buffer in ArcGIS:

A set of polygons (all in one featureclass, circular shapes) should get several buffers (e.g. 40 times). Each feature gets a different buffer distance, it is stored in corresponding field in attribute table. So the first buffer distance is taken from value in table, the following are calculated by "buffer*i", "i" is counting from 1 to 40. For example:
If first feature has the value 400 metres, first buffer for that feature would be 400 metres, 2nd 800 metres, 3rd 1200 metres,.... (measured from the origin shape).

I had two attempts, both are not working the way I like:

import arcpy
arcpy.env.workspace = r"R:\Base.gdb"
fc = "export"
fieldname = "Buffer"
i = 1
while i <= 40:
    outName = fc+"_" + str(i)
    dist = (fieldname)*i
    arcpy.Buffer_analysis(fc, outName, dist)
    i = i+1

Result: First Buffer OK, then abortion, because cannot find fieldname "BufferBuffer" (sure, multiplication of fieldname, but how to calculate with value and not with the name?).

import arcpy
arcpy.env.workspace = r"R:\Base.gdb"
fc = "export"
fieldname = "Buffer"
cursor = arcpy.SearchCursor(fc)
row = cursor.next()
i = 1
while i <= 40:
    outName = fc+"_" + str(i)
    dist = row.getValue(fieldname)*i
    arcpy.Buffer_analysis(fc, outName, dist)
    i = i+1

Result: No Abortion, but all buffers are calculated based on one value from first feature in attribute table, not the corresponding.

In case of using QGis, there are some plugins for multiple buffer, but they work just with static values.

Maybe it's just a short fix in code, who could help me?

Link to comment
Share on other sites

Check the Script of multi ring buffer:

 

"""----------------------------------------------------------------------------------
 Tool Name:   Multiple Ring Buffer
 Source Name: MultiRingBuffer.py
 Author:      Environmental Systems Research Institute Inc.
 Required Arguments:
              An input feature class or feature layer
              An output feature class
              A set of distances (multiple set of double values)
 Optional Arguments:
              The name of the field to contain the distance values (default="distance")
              Option to have the output dissolved (default="ALL")
 Description: Creates a set of buffers for the set of input features. The buffers
              are defined using a set of variable distances. The resulting feature
              class has the merged buffer polygons with or without overlapping
              polygons maintained as separate features.
----------------------------------------------------------------------------------"""

import arcpy
import os
import locale


# Define message constants so they may be translated easily
msgBuffRings = arcpy.GetIDMessage(86149)  # "Buffering distance "
msgMergeRings = arcpy.GetIDMessage(86150)  # "Merging rings..."
msgDissolve = arcpy.GetIDMessage(86151)  # "Dissolving overlapping boundaries..."


def initiate_multi_buffer():
    """Gather arguments and set up for createMultiBuffers"""

    # Get the input argument values
    in_features = arcpy.GetParameterAsText(0)
    output = arcpy.GetParameterAsText(1)
    distances = arcpy.GetParameter(2)

    unit = arcpy.GetParameterAsText(3)
    if unit.lower() == 'default':
        unit = ''

    field_name = checkfieldname(arcpy.GetParameterAsText(4), os.path.dirname(output))
    dissolve_type = arcpy.GetParameterAsText(5)
    outside_polygons = arcpy.GetParameterAsText(6)
    if outside_polygons.lower() == 'true':
        side_type = 'OUTSIDE_ONLY'
    else:
        side_type = ''

    create_multi_buffers(in_features, output, distances, unit, field_name, dissolve_type, side_type)


def checkfieldname(field_name, workspace):
    """Validate field name on the workspace as needed"""
    if field_name in ['#', '']:
        return "distance"
    else:
        out_name = arcpy.ValidateFieldName(field_name, workspace)
        out_name = out_name.replace(' ', '_')
        if out_name != field_name:
            arcpy.AddIDMessage('WARNING', 648, out_name)
        return out_name


def lower_license_union(feature_classes):
    """If Union is not licensed for more than 2 inputs at a time, perform Unions in batches"""

    union_fc = None

    tmp_fc = arcpy.Union_analysis(
        feature_classes[0:2],
        arcpy.CreateUniqueName('union', arcpy.env.scratchGDB))[0]

    for fc in feature_classes[2:]:
        if union_fc:
            tmp_fc = union_fc
        union_fc = arcpy.Union_analysis(
            [tmp_fc, fc],
            arcpy.CreateUniqueName('union', arcpy.env.scratchGDB))[0]

        # Delete intermediate data once used by next Union
        try:
            arcpy.Delete_management(tmp_fc)
        except arcpy.ExecuteError:
            # Don't fail for a delete issue
            pass

    return union_fc


def create_multi_buffers(in_features, output, distances, unit, field_name, dissolve_type, side_type):
    """Main multiple ring buffer routine"""

    # Establish place holders for data cleanup
    buffer_list = []
    union_fc = None

    try:
        # Loop through each distance creating a new layer and then buffering the input.
        #  Set the step progressor if there are > 1 rings
        if len(distances) > 1:
            arcpy.SetProgressor('step', '', 0, len(distances))
            step_progressor = True
        else:
            arcpy.SetProgressor('default')
            step_progressor = False

        # Buffer the input for each buffer distance.  If the field_name is different than
        #  the default, add a new field and calculate the proper value
        for dist in distances:
            if step_progressor:
                arcpy.SetProgressorPosition()
            arcpy.SetProgressorLabel(msgBuffRings + '{}...'.format(dist))
            buf_distance = '{} {}'.format(dist, unit)
            buf_output = arcpy.Buffer_analysis(in_features,
                                               arcpy.CreateUniqueName('buffer', arcpy.env.scratchGDB),
                                               buf_distance, side_type, '', dissolve_type)[0]
            buffer_list.append(buf_output)
            if field_name.lower() != 'buff_dist':
                arcpy.AddField_management(buf_output, field_name, 'double')
                arcpy.CalculateField_management(buf_output, field_name, dist, 'PYTHON')


        arcpy.ResetProgressor()
        arcpy.SetProgressor('default')
        arcpy.SetProgressorLabel(msgMergeRings)

        if dissolve_type == 'ALL':
            # Set up the expression and codeblock variables for CalculateField to ensure
            #  the distance field is populated properly
            expression = 'pullDistance({}, '.format(distances)
            for fc in buffer_list:
                expression += '!FID_{}!, '.format(os.path.basename(fc))
            expression = expression[:-2] + ')'

            # If we have a full license then Union all feature classes at once, otherwise
            #  Union the feature classes 2 at a time
            if arcpy.ProductInfo().upper() in ['ARCINFO', 'ARCSERVER'] or len(buffer_list) < 3:
                union_fc = arcpy.Union_analysis(buffer_list,
                                                arcpy.CreateUniqueName('union', arcpy.env.scratchGDB))[0]
                codeblock = '''def pullDistance(distL, *fids):
                return min([i for i, j in zip(distL, fids) if j != -1])'''
            else:
                union_fc = lower_license_union(buffer_list)
                codeblock = '''def pullDistance(distL, *fids):
                return min([i for i, j in zip(distL, fids) if j == 1])'''

            arcpy.CalculateField_management(union_fc, field_name, expression, 'PYTHON', codeblock)

            # Complete the final Dissolve
            arcpy.SetProgressorLabel(msgDissolve)
            if dissolve_type.upper() == 'ALL':
                arcpy.Dissolve_management(union_fc, output, field_name)
        else:
            # Reverse the order of the inputs so the features are appended from
            #  largest to smallest buffer features.
            buffer_list.reverse()
            template = buffer_list[0]
            sr = (arcpy.env.outputCoordinateSystem or arcpy.Describe(template).spatialreference)

            arcpy.CreateFeatureclass_management(os.path.dirname(output),
                                                os.path.basename(output),
                                                'POLYGON',
                                                template,
                                                'SAME_AS_TEMPLATE',
                                                'SAME_AS_TEMPLATE',
                                                sr)
            for fc in buffer_list:
                arcpy.Append_management(fc, output, 'NO_TEST')

            if arcpy.ListFields(output, 'buff_dist'):
                # Remove duplicate field
                arcpy.DeleteField_management(output, 'buff_dist')

        # Set the default symbology
        params = arcpy.GetParameterInfo()
        if len(params) > 0:
            params[1].symbology = os.path.join(arcpy.GetInstallInfo()['InstallDir'],
                                               "arctoolbox\\templates\\layers\\multipleringbuffer.lyr")

    except arcpy.ExecuteError:
        arcpy.AddError(arcpy.GetMessages(2))

    except Exception as err:
        arcpy.AddError(err)

    finally:
        if buffer_list:
            for fc in buffer_list:
                try:
                    arcpy.Delete_management(fc)
                except arcpy.ExecuteError:
                    # Don't fail for a delete issue
                    pass
        if union_fc:
            try:
                arcpy.Delete_management(union_fc)
            except arcpy.ExecuteError:
                # Don't fail for a delete issue
                pass


if __name__ == '__main__':
    initiate_multi_buffer()

Link to comment
Share on other sites

I think you should use cursors like this

input_fc="fc"

field = "buffer_value_field"

output = "fc_somewhere"

output_temp = "fc_somewhereElse"

cursor = arcpy.da.SearchCursor(input_fc)

for row in cursor:

    arcpy.analysis.Buffer(input_fc,row.getValue(field),output_temp)

    arcpy.management.Append(output_temp,output,"NO_TEST")

    arcpy.management.Delete(output_temp)

 

it does not work in the append process, I just made a conceptual example for you

Edited by yousef2233
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.

Disable-Adblock.png

 

If you enjoy our contents, support us by Disable ads Blocker or add GIS-area to your ads blocker whitelist