0

I have a city park layer that has several multi-part features. I would like to dissolve these into single part features using the Aggregate Polygon tool. I cannot use the Dissolve tool because most of these multi-parts are not directly adjacent to each other. There are highways and waterways separating the parts by up to 300'. But the individual parts have the same ParkID value, so I would like to use this field to identify the aggregated shapefile records.

Pre-Aggregate post_Aggregate

In the second image, you see green polygons that are not park of the red park. I would like to model or script a tool that would aggregate these too, based on their respective park names/IDs

asked Nov 6, 2017 at 20:30
6
  • 2
    How wide are the gaps? A quick method if you're not too fussy is to buffer out by X with dissolve by ParkID then buffer in by -X with no dissolve, where X is just over half the average gap. Most boundaries will end up exactly where they were but you will get some deformation at sharp corners and where the gap is bridged... so long as you don't look too hard it should be OK. The parks are based on cadastre so you could try to obtain the R parcels (assuming Australia, that looks like Canberra) and do polygon neighbors but that gets more complicated. Commented Nov 6, 2017 at 20:50
  • Thanks for the response. The gaps are anywhere from 20 - 500 feet. Doing this spatially I do not think is an option. My idea is to aggregate the common-named polygons. Selecting a distance would be irrelevant because only the common polygons would be aggregated at one time. This is in NYC by the way, Flushing Meadow Park Commented Nov 7, 2017 at 21:58
  • Have a look at Aggregate Polygons resources.arcgis.com/en/help/main/10.2/index.html#//… (advanced license required) and give it a shot with both buffer out/buffer in and aggregate polygons if you have an advanced license and see if the results are suitable for you... it shouldn't take too long to perform. Commented Nov 8, 2017 at 2:40
  • Yes that is the tool I've been using but it won't aggregate according to park name. I would have to manually select all the polygons for each individual park, and iterate the process for every park in the city. Commented Nov 8, 2017 at 2:48
  • Hmm, that is a problem, did you try buffer out/in? Do you have any experience with python? Iterating over unique values is fairly straightforward. What happens to the fields when you use Aggregate Polygon? Commented Nov 8, 2017 at 2:59

1 Answer 1

1

Here's a moderate python script that you can use, both for this task and a learning resource, it should be almost exactly what you need:

import os, sys, arcpy
InFC = sys.argv[1] # Input feature class with parks TYPE: Feature Class
MField = sys.argv[2] # Field to dissolve by TYPE:Field, derived from InFC
OutFC = sys.argv[3] # Output feature class TYPE: Feature Class, direction: output
AggDst = sys.argv[4] # distance for aggregation TYPE: Linear Unit
OutputCreated = False
TempDir = os.environ.get("TEMP") # where to put the temp stuff
TempAgg = os.path.join(TempDir,"TempAgg.shp") # temporary aggregation
MFieldFields = arcpy.ListFields(InFC,MField) # check the intended fields, should be a list of 1 element
if MFieldFields == None:
 arcpy.AddError("Problem negotiating field")
 sys.exit(-1) # exit script
MField_Field = MFieldFields[0]
# count the unique values in the field, using upper case field values as keys
InFeatDict = {}
with arcpy.da.SearchCursor(InFC,MField) as SCur:
 for row in SCur: # iterate the rows (features)
 if row[0].upper() in InFeatDict:
 InFeatDict[row[0].upper()] += 1 # increment the count of this key by 1
 else:
 InFeatDict[row[0].upper()] = 1 # set the count of this new key to 1
for ThisKey in InFeatDict:
 arcpy.AddMessage("Aggregating {} for {} feature(s)".format(ThisKey,InFeatDict[ThisKey]))
 # make a feature layer with just this value
 arcpy.MakeFeatureLayer_management(InFC,"Layer","upper({}) = '{}'".format(MField,ThisKey))
 if InFeatDict[ThisKey] == 1:
 if OutputCreated:
 arcpy.Append_management("Layer",OutFC,"NO_TEST") # add the feature directly to the output
 else:
 arcpy.CopyFeatures_management("Layer",OutFC) # export the single feature to new output
 OutputCreated = True
 else:
 # More than one feature for this key
 # get the 'real' value in the first row to calculate
 with arcpy.da.SearchCursor("Layer",MField) as sCur:
 for row in sCur:
 FieldValue = row[0]
 arcpy.AddMessage("Output will have value {}".format(FieldValue))
 break
 arcpy.AggregatePolygons_cartography("Layer",TempAgg,AggDst) # aggregation done here
 # add a field of the correct type, annoyingly the value returned by Field.type is not the
 # same as what is supplied to addfield type, the conversion follows:
 if MField_Field.type == 'String':
 arcpy.AddField_management(TempAgg,MField,"TEXT",field_length = MField_Field.length)
 elif MField_Field.type == 'Double':
 arcpy.AddField_management(TempAgg,MField,"DOUBLE")
 elif MField_Field.type == 'Integer':
 arcpy.AddField_management(TempAgg,MField,"LONG")
 elif MField_Field.type == 'SmallInteger':
 arcpy.AddField_management(TempAgg,MField,"SHORT")
 elif MField_Field.type == 'Single':
 arcpy.AddField_management(TempAgg,MField,"FLOAT")
 # calculate the field with the value before appending
 if MField_Field.type == 'String':
 arcpy.CalculateField_management(TempAgg,MField,'\"{}\"'.format(FieldValue)) # quoted for strings
 else:
 arcpy.CalculateField_management(TempAgg,MField,FieldValue) # unquoted for numbers
 # now either append or copy the temp aggregated and calculated features to the output
 if OutputCreated:
 arcpy.Append_management(TempAgg,OutFC,"NO_TEST") # add the feature directly to the output
 else:
 arcpy.CopyFeatures_management(TempAgg,OutFC) # export the single feature to new output
 OutputCreated = True
 # Clean up
 arcpy.Delete_management(TempAgg)
 arcpy.Delete_management("Layer")

Set it up in either an existing or new toolbox (refer Adding a Script Tool from Esri help) with parameters as mentioned in the comments for the inputs like this:enter image description here

Note that the output will probably only have the one field that you specify to aggregate by.

answered Nov 9, 2017 at 2:23
3
  • Wow, that is a wonderful script, but at this time it is way over my head. Any ideas on how to approach it using the model builder? I'm going to spend time looking at this but It might take me less time to do it manually! Commented Nov 9, 2017 at 2:56
  • I don't think modelbuilder has the scope to do this. I've tested that script and validated the outputs, it may look complicated but that's partly because I have made it general (for all field types, number of features etc..). You don't need to understand the python to use it, perhaps have a read of the Adding a script tool, copy/paste the script as written into notepad, save as type .py then add to a new toolbox. It will probably be very close to what you need. Commented Nov 9, 2017 at 3:18
  • I am experimenting with an iterator tool (iterate feature selection) which allows you to group by a field value. Seems like a step in the right direction but it still won't aggregate right Commented Nov 30, 2017 at 19:36

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.