I wrote a Python script that would get you part way there: http://forums.arcgis.com/threads/17809-polygon-in-polygon-analysis-count-if?p=56528&viewfull=1#post56528 The script basically does a recursive SelectByLocation (maybe specify 1 mile selction radius?). The FC then gets a CLUSTER_ID field (you can name it whatever you want) added and populated. So if there were three "clusters" of points that were > 1 mile appart (but the points in the cluster were all < 1 mile appart) you would end up with 3 different CLUSTER_ID values. Then all you need to do is add the X and Y coordinates to the table, run the Summary Statistics tool (using CLUSTER_ID as the case field, and getting the mean X and Y coordinate values). Build a new FC based on teh output of the summary stats table. Presto.
# Description # ----------- # This script assigns a unique identifier to features that are connected/close to each other. # This may be useful for identifying interconnected networks of polygons or lines such as a road # or stream networks. It is particularly useful when trying to do large single part dissolves... # just dissolve by the unique identifier field (or in addition to other fields as well). # # Written By: Chris Snyder, WA DNR, 7/27/2007, chris.snyder(at)wadnr.gov # # Written For: Python 2.4.1 and ArcGIS v9.2 SP2 # #Notes on input parameters: #VARIABLE PAREMETER_INDEX PARAMETER_DATA_TYPE #------------------------------------------------------------------- #inLayer 0 Feature Layer #networkIdField 1 Text (for example, "NET_ID") #new long int field that will be added #selectionMethod 2 Text (for example, "INTERSECT") - this needs to be one of the selection keywords used in the SelectByLocation tool #distThreshold 3 Linear Unit (for example, "1 METER") only used if selectionMethod = "WITHIN_A_DISTANCE" # Import system modules and creates the Geoprocessor object try: #Import system modules and creates the Geoprocessor object (the v9.2 way) import sys, string, os, glob, shutil, time, traceback, arcgisscripting gp = arcgisscripting.create() #Defines some functions used for getting messages from the gp and python def showGpMessage(): gp.AddMessage(gp.GetMessages()) print >> open(logFile, 'a'), gp.GetMessages() print gp.GetMessages() def showGpWarning(): gp.AddWarning(gp.GetMessages()) print >> open(logFile, 'a'), gp.GetMessages() print gp.GetMessages() def showGpError(): gp.AddError(gp.GetMessages()) print >> open(logFile, 'a'), gp.GetMessages() print gp.GetMessages() def showPyMessage(): gp.AddMessage(str(time.ctime()) + " - " + message) print >> open(logFile, 'a'), str(time.ctime()) + " - " + message print str(time.ctime()) + " - " + message def showPyWarning(): gp.AddWarning(str(time.ctime()) + " - " + message) print >> open(logFile, 'a'), str(time.ctime()) + " - " + message print str(time.ctime()) + " - " + message def showPyError(): gp.AddError(str(time.ctime()) + " - " + message) print >> open(logFile, 'a'), str(time.ctime()) + " - " + message print str(time.ctime()) + " - " + message #Sets a date/time stamp variable in the format yyyymmddhhmmss (example: 20060711132345) dateTimeStamp = time.strftime('%Y%m%d%H%M%S') #Specifies the root directory variable, defines the logFile variable, and does some minor error checking... dateTimeString = str(time.strftime('%Y%m%d%H%M%S')) scriptName = os.path.split(sys.argv[0])[-1].split(".")[0] userName = string.lower(os.environ.get("USERNAME")).replace(" ","_").replace(".","_") tempPathDir = os.environ["TEMP"] logFileDirectory = r"\\snarf\am\div_lm\ds\gis\tools\log_files" if os.path.exists(logFileDirectory) == True: logFile = os.path.join(logFileDirectory, scriptName + "_" + userName + "_" + dateTimeString + ".txt") try: print >> open(logFile, 'a'), "Write test successfull!" except: logFile = os.path.join(tempPathDir, scriptName + "_" + userName + "_" + dateTimeString + ".txt") else: logFile = os.path.join(tempPathDir, scriptName + "_" + userName + "_" + dateTimeString + ".txt") if os.path.exists(logFile)== True: os.remove(logFile) message = "Created log file " + logFile; showPyMessage() message = "Running " + sys.argv[0]; showPyMessage() #Attempts to check out the lowest grade license available... if gp.CheckProduct("ArcView") == "Available": gp.SetProduct("ArcView") elif gp.CheckProduct("ArcEditor") == "Available": gp.SetProduct("ArcEditor") elif gp.CheckProduct("ArcInfo") == "Available": gp.SetProduct("ArcInfo") message = "Selected an " + gp.ProductInfo() + " license"; showPyMessage() message = "Starting geoprocessing routine..."; showPyMessage() #*****************GEOPROCESSING STUFF GOES HERE****************************** #Process: Sets some gp settings gp.overwriteoutput = 1 #Defines the input feature layer inLayer = gp.GetParameterAsText(0) networkIdField = gp.GetParameterAsText(1) selectionMethod = gp.GetParameterAsText(2) distThreshold = gp.GetParameterAsText(3) #Process: Tests for the existance of networkIdField - if it doesn't exists, add it if gp.listfields(inLayer, networkIdField).next() == None: gp.AddField_management(inLayer, networkIdField, "LONG"); showGpMessage() else: message = "Specified existing field type is: " + str(gp.listfields(inLayer, networkIdField).next().type); showPyMessage() if gp.listfields(inLayer, networkIdField).next().type not in ["SmallInteger","Double","Integer"]: message = "ERROR: Existing specified network id field type must be Long Integer, Short Integer or Double! Exiting script..."; showPyError(); sys.exit() gp.CalculateField_management(inLayer, networkIdField, "0", "VB"); showGpMessage() #makes sure the field is nulled #Process: Figures out how many features are in the input feature class featureCount = int(gp.getcount(gp.describe(inLayer).catalogpath)) #Process: Figures out what the oidValue field is called oidFieldName = gp.describe(inLayer).oidfieldname #Process: Does a recursive select by location featureLayer1 = "feature_layer_1" featureLayer2 = "feature_layer_2" identifiedFeatures = 0 networkId = 0 gp.MakeFeatureLayer_management(inLayer, featureLayer1, "") while identifiedFeatures < featureCount: #Process: Assign a counter networkId = networkId + 1 #Process: Establishes a cursor in order to return a single OID of a non-identified feature try: #this is in a try loop cause' it will fail on the last loop since networkIdField will be (hopefully) 100% populated oidValue = gp.searchcursor(inLayer, networkIdField + " = 0 OR " + networkIdField + " IS NULL").next().getvalue(oidFieldName) except: message = "Breaking selection loop..."; showPyMessage() break #break out of the loop gp.SelectLayerByAttribute_management(featureLayer1, "NEW_SELECTION", oidFieldName + " = " + str(oidValue)) #Process: Keep selecting features until there are no more to select count1 = 0 count2 = 1 count3 = 0 while count2 > count1: count3 = count3 + 1 count1 = int(gp.getcount(featureLayer1)) if selectionMethod == "WITHIN_A_DISTANCE": gp.SelectLayerByLocation_management(featureLayer1, "WITHIN_A_DISTANCE", featureLayer1, distThreshold, "NEW_SELECTION") else: gp.SelectLayerByLocation_management(featureLayer1, selectionMethod, featureLayer1, "", "NEW_SELECTION") count2 = int(gp.getcount(featureLayer1)) if divmod(count3, 10)[1] == 0: message = "Processed the " + str(count3) + "th loop of connected feature ID #" + str(networkId) + "..."; showPyMessage() gp.CalculateField_management(featureLayer1, networkIdField, networkId, "VB") #Process: Every 25th loop, spit out a status message (too many status messages makes the script run slow) if divmod(networkId, 25)[1] == 0: gp.MakeFeatureLayer_management(inLayer, featureLayer2, networkIdField + " > 0") identifiedFeatures = int(gp.getcount(featureLayer2)) message = "Assigned identifier to " + str(float(identifiedFeatures) / float(featureCount) * 100) + " percent of the features"; showPyMessage() #Process: Gives a final report gp.MakeFeatureLayer_management(inLayer, featureLayer2, networkIdField + " > 0") identifiedFeatures = int(gp.getcount(featureLayer2)) gp.MakeFeatureLayer_management(inLayer, featureLayer2, networkIdField + " = 0 OR " + networkIdField + " IS NULL") nonIdentifiedFeatures = int(gp.getcount(featureLayer2)) message = "CONNECTED FEATURES REPORT:"; showPyWarning() message = "--------------------------"; showPyWarning() message = "Assigned " + str(networkId -1) + " unique network identifiers to " + str(identifiedFeatures) + " features!"; showPyWarning() #*****************GEOPROCESSING STUFF ENDS HERE****************************** message = "Ending geoprocessing routine..."; showPyMessage() #Indicates that the script is complete - both a visual and physical indicator... message = sys.argv[0] + " is all done!"; showPyMessage() except: message = "\n*** LAST GEOPROCESSOR MESSAGE (may not be source of the error)***"; showPyError() showGpMessage() message = "PYTHON TRACEBACK INFO: " + traceback.format_tb(sys.exc_info()[2])[0]; showPyError() message = "PYTHON ERROR INFO: " + str(sys.exc_type)+ ": " + str(sys.exc_value) + "\n"; showPyError()
Signed in members can post, follow updates, and more. New here? Register a free account.
Find useful guides, FAQs, and documents to help you navigate and make the most of Esri Community.