You CAN do it using vectors, 100% agree with others. Anyway, I slightly modified your code, replacing very long names and it works as expected:
import arcpy
store_buffs = r"D:\Scratch\A30min_weekday.shp"
density_ras = r"D:\Scratch\Raster1.tif"
table_list = []
with arcpy.da.SearchCursor(store_buffs, ["FacilityID"]) as cursor:
for row in cursor:
arcpy.AddMessage(row[0])
exp = '"FacilityID" = ' + str(row[0])
temp_table10 = r"in_memory\temp_" + str(row[0])
temp_shp10 = r'in_memory\temp_shp10'
arcpy.Select_analysis(store_buffs, temp_shp10, exp)
arcpy.sa.ZonalStatisticsAsTable(temp_shp10, 'FacilityID', density_ras, temp_table10, 'DATA', 'SUM')
table_list.append(temp_table10)
del row
final_table = r"D:\scratch\all_rows.dbf"
arcpy.Merge_management(table_list, final_table)
It takes ages, i.e. almost 4 mins for 100 pgons.
Try this one, it takes 25 sec to do the same job. It works from ArcMap, assumes you have layer called 'A30min_weekday' and it has field SUM.
import arcpy, traceback, os, sys
from arcpy import env
env.overwriteOutput = True
mxd = arcpy.mapping.MapDocument("CURRENT")
store_buffs=arcpy.mapping.ListLayers(mxd,'A30min_weekday')[0]
density_ras = r"D:\Scratch\Raster1.tif"
parID="FacilityID"
parID2="FacilityID_1"
env.workspace = "in_memory"
dbf="stat"
joinLR="SD"
try:
def showPyMessage():
arcpy.AddMessage(str(time.ctime()) + " - " + message)
def Get_V(aKey):
try:
return smallDict[aKey]
except:
return (-1)
arcpy.AddMessage("Defining neighbours...")
arcpy.SpatialJoin_analysis(store_buffs, store_buffs, joinLR,"JOIN_ONE_TO_MANY")
arcpy.AddMessage("Creating empty dictionary")
dictFeatures = {}
with arcpy.da.SearchCursor(store_buffs, parID) as cursor:
for row in cursor:
dictFeatures[row[0]]=()
del row, cursor
arcpy.AddMessage("Assigning neighbours...")
with arcpy.da.SearchCursor(joinLR, (parID,parID2)) as cursor:
for row in cursor:
aKey=row[0]
aList=dictFeatures[aKey]
aList+=(row[1],)
dictFeatures[aKey]=aList
del row, cursor
arcpy.AddMessage("Defining non-overlapping subsets...")
runNo=0
while (True):
toShow,toHide=(),()
nF=len(dictFeatures)
for item in dictFeatures:
if item not in toShow and item not in toHide:
toShow+=(item,)
toHide+=(dictFeatures[item])
m=len(toShow)
quer='"FacilityID" IN '+str(toShow)
if m==1:
quer='"FacilityID" = '+str(toShow[0])
store_buffs.definitionQuery=quer
runNo+=1
arcpy.AddMessage("Run %i, %i polygon(s) found" % (runNo,m))
arcpy.AddMessage("Running Statistics...")
arcpy.gp.ZonalStatisticsAsTable_sa(store_buffs, parID, density_ras, dbf, "DATA", "SUM")
arcpy.AddMessage("Data transfer...")
smallDict={}
with arcpy.da.SearchCursor(dbf, (parID,"SUM")) as cursor:
for row in cursor:
smallDict[row[0]]=row[1]
del row, cursor
with arcpy.da.UpdateCursor(store_buffs, (parID,"SUM")) as cursor:
for row in cursor:
aKey=row[0]
row[1]=Get_V(aKey)
cursor.updateRow(row)
del row, cursor
for item in toShow:
del dictFeatures[item]
m=len(dictFeatures)
if m==0:
break
store_buffs.definitionQuery=""
except:
message = "\n*** PYTHON ERRORS *** "; showPyMessage()
message = "Python Traceback Info: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyMessage()
message = "Python Error Info: " + str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyMessage()
Best Answer
This is a graph coloring problem.
Recall that a graph coloring is an assignment of a color to the vertices of a graph in such a way that no two vertices which share an edge will also have the same color. Specifically, the (abstract) vertices of the graph are the polygons. Two vertices are connected with an (undirected) edge whenever they intersect (as polygons). If we take any solution to the problem--which is a sequence of (say k) disjoint collections of the polygons--and assign a unique color to each collection in the sequence, then we will have obtained a k-coloring of the graph. It is desirable to find a small k.
This problem is pretty hard and remains unsolved for arbitrary graphs. Consider an approximate solution that's simple to code. A sequential algorithm ought to do. The Welsh-Powell algorithm is a greedy solution based on a descending ordering of the vertices by degree. Translated to the language of the original polygons, first sort the polygons in descending order of the number of other polygons they overlap. Working in order, give the first polygon an initial color. In each successive step, try to color the next polygon with an existing color: that is, choose a color that is not already used by any of that polygon's neighbors. (There are many ways to choose among the available colors; try either the one that has been least used or else choose one randomly.) If the next polygon cannot be colored with an existing color, create a new color and color it with that.
Once you have achieved a coloring with a small number of colors, perform zonalstats color by color: by construction, you're guaranteed that no two polygons of a given color overlap.
Here's sample code in
R
. (Python code wouldn't be much different.) First, we describe overlaps among the seven polygons shown.That is, polygons 1 and 2 overlap, and so do polygons 2 and 3, 3 and 4, ..., 1 and 7.
Sort the vertices by descending degree:
A (crude) sequential coloring algorithm uses the earliest available color not already used by any overlapping polygon:
Initialize the data structures (
colors
andcolor.next
) and apply the algorithm:Split the polygons into groups according to color:
The output in this example uses four colors:
It has partitioned the polygons into four non-overlapping groups. In this case the solution is not optimal ({{3,6,5}, {2,4}, {1,7}} is a three-coloring for this graph). In general the solution it gets shouldn't be too bad, though.