Select to view content in your preferred language

Zonal Statistics as Table: Overlapping Polygons: Solution Required

28907
63
08-09-2011 07:01 AM
PeterWilson
Frequent Contributor
I'm currently using ArcGIS 10 SP2 on Windows 7 64bit. I'm working on a very large railway alignment design project and need to generate "Average Catchment Slopes" for each watershed. The problem that I have is that the "Zonal Statistics as Table" tool does not process overlapping polygons. It's mentions in the help that if the polygons overlap, that should be processed interactively to overcome this. I haven't been able to find any supporting documentation to achieve this. Just a note, I have over 600 watersheds that I need to process and a manual process will not be possible if I'm to meet my deadline. Any advice will be appreciated.

Regards
63 Replies
curtvprice
MVP Alum
Hi

I'm trying to extraction band information from raster images using overlapping buffers. I tried using Jamie's code and it takes a long time. I can't ran Curtis' code. Does anymore have a code that works faster?


Thanks


Even if you used my current (10x-compatible) version (ftp://ftpext.usgs.gov/pub/nonvisible/cr/nact) it would not be any faster than Jamie's code,as i also do one at a time. Have you tried Sue's tool? I haven't tried it yet, but it seems like a really good solution.
0 Kudos
Xin_RanDing
Emerging Contributor
Even if you used my current (10x-compatible) version (ftp://ftpext.usgs.gov/pub/nonvisible/cr/nact) it would not be any faster than Jamie's code,as i also do one at a time. Have you tried Sue's tool? I haven't tried it yet, but it seems like a really good solution.


I did, but I get errors

Traceback (most recent call last):
  File "Z:\Extraction of Bands\Extraction\Python for extraction\Trial\ZonalStatsOverlappingPolys (2)\makeZones.py", line 170, in <module>
    arcpy.CopyFeatures_management(inFeat, inFeatures)
  File "c:\program files (x86)\arcgis\desktop10.1\arcpy\arcpy\management.py", line 2226, in CopyFeatures
    raise e
ExecuteError: ERROR 000210: Cannot create output Z:\Extraction of Bands\Extraction\Python for extraction\Trial\Scratch.mdb\50m_buffer_P_selection
ERROR 000361: The name starts with an invalid character
Failed to execute (CopyFeatures).


Failed to execute (ZonesWOverlap).
Failed at Wed Oct 31 10:37:07 2012 (Elapsed Time: 8.00 seconds)
0 Kudos
curtvprice
MVP Alum
ERROR 000361: The name starts with an invalid character
Failed to execute (CopyFeatures).


I believe the error (from CopyFeatures, not Sue's script) is telling you to avoid naming datasets starting with a number. I also suggest avoiding spaces in pathnames, it works most of the time but is just asking for trouble -- something will break when you most need it not to.

000361 : The name starts with an invalid character
0 Kudos
Xin_RanDing
Emerging Contributor
I believe the error (from CopyFeatures, not Sue's script) is telling you to avoid naming datasets starting with a number. I also suggest avoiding spaces in pathnames, it works most of the time but is just asking for trouble -- something will break when you most need it not to. 

000361 : The name starts with an invalid character



Hi

I renamed the files and got past that stage but now I'm getting an error of during zonal statistics, apparently it can't read the raster file

Executing: ZonesWOverlap S_buffer OBJECTID Band_1.tif "Z:\Extraction of Bands\Trial Extraction\Trail1\StatisticsForOverlappingZones" F:\Data\xiding\Documents\ArcGIS\Default.gdb\S_buffer_ZonesWOverlap 7
Start Time: Thu Nov 01 13:53:15 2012
Running script ZonesWOverlap...
Selecting the [fCount] = 0...
Feature layer number 1 of 7
Iteration 1, Spatial Join
Iteration 1, Join
Select S_buffer.OBJECTID = j1.OBJECTID_1
Removing Join...
Iteration 1, Zonal Statistics
<class 'arcgisscripting.ExecuteError'>: ERROR 010160: Unable to open raster zLayer. Zonal statistics program failed
ERROR 010067: Error in executing grid expression.
Failed to execute (ZonalStatisticsAsTable).

Failed to execute (ZonesWOverlap).
Failed at Thu Nov 01 13:54:01 2012 (Elapsed Time: 46.00 seconds)
0 Kudos
JamieKass
Regular Contributor
Even if you used my current (10x-compatible) version (ftp://ftpext.usgs.gov/pub/nonvisible/cr/nact) it would not be any faster than Jamie's code,as i also do one at a time. Have you tried Sue's tool? I haven't tried it yet, but it seems like a really good solution.


My original code does not process one feature at a time, rather it attributes all features with an "explode" field that breaks them up into non-overlapping groups, which Zonal Statistics can then be iterated over. My method involves as few arcpy functions as possible to save time, as processing large features often tie up geoprocessing tools that are managing spatial characteristics as well as table data. Essential functions like Identity are run, then cursors pull table data into Python dictionaries, where most of the processing takes place. These functions were built to handle large datasets, so they should perform well even with many features.
I have a newer version of the code I posted last time that's a bit faster (uses da cursor functions and iterates over the dicts less) and cleaner, which I'll post below. It comes in a couple of functions, which can be called separately if need be. If anyone needs help implementing it, please post to this thread.

def makeOverlapDict(fc, returnID = None):
    """This function creates a dictionary relating each feature to a list of its
    overlapping features. The optional returnID parameter can be used to create
    an overlapDict with keys equal to a different unique ID than OID, which is the
    default."""
    fcName = arcpy.Describe(fc).name
    if not returnID:
        returnID = 'FID_' + fcName
        returnID2 = 'FID_' + fcName + '_1'
    else:
        returnID2 = returnID + '_1'

    identity = arcpy.Identity_analysis(fc, fc, fcName + 'ID')

    overlapDict = {}
    with arcpy.da.SearchCursor(identity, (returnID, returnID2)) as cursor:
        for row in cursor:
            if row[0] <> row[1]:
                if not overlapDict.get(row[0]):
                    overlapDict[row[0]] = [row[1]]
                else:
                    overlapDict[row[0]].append(row[1])

    arcpy.Delete_management(identity)

    return overlapDict

def makeExplodeDict(overlapDict):
    """This function creates a new dictionary relating each feature to
    its explode value based on the overlapDict."""

    # set initial explode value to 1
    expl = 1
    # create dictionary to hold explode values of oids
    explDict = {}
    overlapDict2 = overlapDict.copy()
    # while there are still keys in overlapDict2 not also in explDict
    while len([k for k in overlapDict2.iterkeys() if not explDict.get(k)]) > 0:
        # create list to hold overlapping oids
        ovSet = set()
        # loop over overlapDict2
        for oid, ovlps in overlapDict2.iteritems():
            if not explDict.get(oid) and oid not in ovSet:
                explDict[oid] = expl
                for o in ovlps:
                    ovSet.add(o)
        for oid in explDict.iterkeys():
            if overlapDict2.get(oid):
                del overlapDict2[oid]
        print expl
        expl += 1
    return explDict

def defineOverlaps(fc):
    """This function creates three fields: 'overlaps', which lists the OBJECTIDs
    of all other polygons overlapping each polygon, and 'ovlpCount', which counts
    the number of overlaps per feature, and 'expl', which separates all features
    into unique non-overlapping groups by value."""

    # Build dicts used to relate each feature to all identical, overlapping shapes
    overlapDict = makeOverlapDict(fc)

    # Loop through overlapDict and give each oid an expl value that separates all oids into
    # non-overlapping groups
    explDict = makeExplodeDict(overlapDict)

    # Add remaining non-overlapping oids into explDict and give them an expl value
    # equal to the max expl; the max should have the least members, and this preserves
    # a good distribution of values so that each processing step is somewhat balanced
    maxExpl = max(explDict.itervalues())
    query = str(tuple(explDict.keys()))
    fillVals = []
    with arcpy.da.SearchCursor(fc, ("OID@"), '"OBJECTID" NOT IN ' + query) as cursor:
        for row in cursor:
            fillVals.append(row[0])
    for val in fillVals:
        explDict[val] = maxExpl

    # Add overlaps, ovlpCount, and expl fields
    arcpy.AddField_management(fc,'overlaps',"TEXT",'','',1000) # the 1000 is the field character limit... increase if need be
    arcpy.AddField_management(fc,'ovlpCount',"SHORT")
    arcpy.AddField_management(fc,'expl',"SHORT")

    # For each row with an overlapping poly (i.e. with an entry in idDict)
    # give overlaps value of all overlapping ids, ovlpCount value of how
    # many overlaps occur, and expl value that separates all features into
    # unique non-overlapping groups (explode value)

    with arcpy.da.UpdateCursor(fc,("OID@","overlaps","ovlpCount","expl")) as cursor:
        for row in cursor:
            # If oid in overlapDict, write overlapping oids and their count
            # to the appropriate fields
            if overlapDict.get(row[0]):
                row[1] = str(overlapDict[row[0]]).strip('[]')
                row[2] = len(overlapDict[row[0]])
            # Write expl value to expl field
            row[3] = explDict[row[0]]
            cursor.updateRow(row)


If you're using the Python window, once these 3 function definitions have been entered, simply call the operation like this, where 'fc' is your feature class:
defineOverlaps(fc)

Please note that the next step would be to select by attributes based on the 'expl' value and run Zonal Statistics for each value, which will be at most in the tens as long as the features are not too piled up. This can be performed easily with a simple for loop.
0 Kudos
MarkBoucher
Honored Contributor
I did finish the tool I was working on. The tool is faster than the individual polygon solution.  Originally I produced 3 different solutions for breaking up the polygons and ended up using two of those methods.  I have uploaded the tool and documented it.

The tool uses Spatial Join and also breaks up the feature class into smaller pieces.

http://www.arcgis.com/home/item.html?id=b859b33c616a47d2b99b5e133942db02

Every one of my polygons overlap at least one other polygon. Will this tool work for me? Basically, every polygon would have to be process separately, correct? The grouping technique would not work.

0 Kudos
BrendanCollins
Deactivated User
Hey can people vote for this idea to enhance zonal tools:

http://ideas.arcgis.com/ideaView?id=0873000000086QNAAY
0 Kudos
SteveLynch
Esri Regular Contributor
I did, but I get errors

Traceback (most recent call last):
  File "Z:\Extraction of Bands\Extraction\Python for extraction\Trial\ZonalStatsOverlappingPolys (2)\makeZones.py", line 170, in <module>
    arcpy.CopyFeatures_management(inFeat, inFeatures)
  File "c:\program files (x86)\arcgis\desktop10.1\arcpy\arcpy\management.py", line 2226, in CopyFeatures
    raise e
ExecuteError: ERROR 000210: Cannot create output Z:\Extraction of Bands\Extraction\Python for extraction\Trial\Scratch.mdb\50m_buffer_P_selection
ERROR 000361: The name starts with an invalid characterFailed to execute (CopyFeatures).


Failed to execute (ZonesWOverlap).
Failed at Wed Oct 31 10:37:07 2012 (Elapsed Time: 8.00 seconds)


Output in a geodatabase must start with an alphabetic character, yours starts with the number 5
0 Kudos
manisharai
New Contributor
I've been posting updated versions here for review, please use at your own risk and send comments:

ftp://ftpext.usgs.gov/pub/nonvisible/cr/nact


Hi Curtis,

I am a PhD student and was using the NAWQA tool for ArcGIS 9.3 for my research. However, I upgraded to version 10.1 and couldn't run the NAWQA tool anymore. So, I downloaded the file that you listed in your post for version 10.x. I am trying to calculate mean elevations around some sites in CA. I use the Feature statistics to table tool from the NACT toolbox and set the buffer distance to say 500m. The tool runs fine for some sites and then I start getting these error messages :

Zonal statistics could not be computed for feature 26 (zone = 26)
ERROR 000601: Cannot delete C:\Research\Projects\xxxwk1\xx.gdb\workfeat.  May be locked by another application.
Failed to execute (CopyFeatures).

I do not have any other application running (arc catalogue, IDLE) that could possibly be causing a lock. I have no experience with coding in ArcGIS so I am not able to figure out the problem on my own by looking at the code.

I hope you could help me with this.

Thanks.

Manisha
0 Kudos
curtvprice
MVP Alum
Zonal statistics could not be computed for feature 26 (zone = 26)
ERROR 000601: Cannot delete C:\Research\Projects\xxxwk1\xx.gdb\workfeat. May be locked by another application.
Failed to execute (CopyFeatures).


Manisha, I don't think the above error has do with my tool. There have been reports of antivirus software locking ArcGIS files while they are being scanned, and making things miserable for everyone.

I honestly don't have any good ideas for you. Can you try on a different machine that may have different security set up?
0 Kudos