4

I've got a script that takes a single input polygon feature, throws 10 buffers around it at tenths of a specified input distance, and then symbolises the output based on an existing layer file. Pretty simple.

However, the arcpy.MultipleRingBuffer_analysis operation is amazingly slow. It takes upwards of two minutes to generate the buffers, even for very basic polygon inputs - the same result can be had in about two seconds by using the buffer wizard tool. Problem is, the buffer wizard can't be accessed through arcpy.

So obviously it's possible to quickly generate multiple ring buffers - does anyone have any insight as to how the buffer wizard tool is doing it, and how that might be replicated in Python?

9
  • It would be an interesting exercise to compile a chart of actual numbers, but it takes a great deal of time to just invoke arcpy and grab license, even before getting to any real work. I've seen import arcpy take 10s of seconds on its own. Commented Dec 19, 2012 at 6:04
  • 1
    Just a note of caution: I've found the Multiple Ring Buffer wizard to be buggy. I have had situations where it failed to generate the rings as specified. However, the error does not seem to be consistent. I only noticed this problem since version 10. Prior to that it behaved itself. Commented Dec 19, 2012 at 9:43
  • @notaprogrammer Are you using ArcGIS 10.0 or 10.1?
    – dmahr
    Commented Dec 19, 2012 at 14:44
  • 10.1, if that helps.
    – Nathaniel
    Commented Dec 19, 2012 at 22:42
  • @dmahr may be thinking along the lines of writing a Python Add-in for ArcMap which 10.1 opens up the opportunity for - I suspect that could be used to write a faster Multiple Ring Buffer for use in ArcMap but have not had chance to test it yet
    – PolyGeo
    Commented Dec 20, 2012 at 0:47

2 Answers 2

1

While the buffer wizard is not exposed through ArcPy, geometries do expose the buffer method so the following works to create multiple ring buffers:

import arcpy

def MultiRingBuffer(ringDistance, ringCount, inputLayer, outputLayer):
    buffers = []

    cursor = arcpy.SearchCursor(inputLayer)
    for inputFeature in cursor:
        sourceOid = inputFeature.getValue("OBJECTID")
        currentBuffers = dict()
        buffers.append(currentBuffers)
        prevBuffer = inputFeature.Shape

        for multiple in range(1, ringCount + 1):
            distance = multiple * ringDistance
            bufferedGeom = inputFeature.Shape.buffer(distance)
            bufGeom = bufferedGeom.difference(prevBuffer)
            prevBuffer = bufferedGeom
            row = dict()
            row["sourceOid"] = sourceOid
            row["distance"] = distance
            row["SHAPE"] = bufGeom
            currentBuffers[distance] = row
    del cursor

    cursor = arcpy.InsertCursor(outputLayer)
    for ringBuffers in buffers:
        for feature in ringBuffers.values():
            row = cursor.newRow()
            for k in feature.keys():
                if k == "SHAPE":
                    row.Shape = feature[k]
                else:
                    row.setValue(k, feature[k])
            cursor.insertRow(row)
    del cursor

if __name__ == '__main__':
    MultiRingBuffer(10, 10, "c:\\temp\\test.gdb\\buffertest", "c:\\temp\\test.gdb\\bufferout")
    print("Complete")

For each source feature, we create a dictionary to store each ring buffer. Each of these buffers is a dictionary with a few values - the source OID, the distance, and the buffer geometry. We then create an insert cursor and create features in the output table for each ring buffer of each input feature.

Edit: I have tested this and with 3 simple features, where the gp tool takes over a minute, this script takes ~1s once arcpy has finished importing.

Edit 2: Fixed a couple of bugs - firstly, the difference call was removing the previous ring rather than all previous rings. Secondly, I wasn't adding the ring to the currentBuffer so it wasn't getting added later...

Edit 3: Handled the shape field not being 'SHAPE' in the output featureclass. Added cleanup of cursor objects.

6
  • Thanks for this, it looks promising. I couldn't get any output though. I can get things to a point where it looks like the script is running (it runs very quickly, as you said), but nothing appears to be altered in the input or output feature classes. How exactly did you set up your test, so that I can try to replicate your results?
    – Nathaniel
    Commented Jan 23, 2015 at 6:12
  • Thank you, there were a couple of bugs in there. In the loop that actually calls Shape.buffer I've made a couple of changes - first, to separate the buffer and difference, so the plain buffered geometry can be used for subsequent differences, and secondly to actually add the row dictionary to the currentBuffers dictionary Commented Jan 23, 2015 at 10:15
  • It's still falling over for me at the last row.setvalue line. I can see what it's supposed to do, but I don't know enough Python to fix it. Any ideas?
    – Nathaniel
    Commented Jan 28, 2015 at 7:05
  • Could be that your shape field isn't called 'SHAPE'? It certainly doesn't have to be, I only used that as a shortcut. Could you post the error it's giving please? And I'll edit the above to use the row's shape property just in case that's it (and it's more correct anyway). Commented Jan 29, 2015 at 9:03
  • It could also be missing fields in the output feature class - it needs to have be a polygon feature class with two long integer fields called 'sourceOid' and 'distance'. Change the row dictionary entries in the first loop to change what attributes are set in the output feature class. Commented Jan 29, 2015 at 9:11
1

Unfortunately, the Buffer wizard (and its options) are not exposed in ArcObjects or ArcPy.

I'm trying to think of ways around this. One cool thing about the Buffer wizard is that you can use an optimized coordinate system at either a selected feature set / entire dataset or feature level. If you're using the former (not the feature-optimized), and your data is using a geographic coordinate reference system, you might try projecting your data into a projected coordinate system, then running the Buffer Tool.

Note: I work for Esri.

2
  • 1
    Hi @mkennedy - thanks for your comment. I don't know what an optimized coordinate system is, but I am using features that have been projected into a proj. coord. system. If you have any sway in this at ESRI, can you ask why the Buffer Wizard a) is so buried in tools so that only an exhaustive Google search eventually leads to an Esri blog post that reveals its existence? and b) why can't it just retain the other fields in the outputs from the input features like almost every other tool?
    – SharonB
    Commented Sep 9, 2013 at 16:11
  • I know your response is from a couple of years ago @SharonB but I found this article that might help shed some light on what an "optimized coordinate system" is. It's worth adding for any users that may be in the same boat coming across this question.
    – Sethdd
    Commented Mar 27, 2017 at 17:28

Your Answer

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

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