Vous êtes sur la page 1sur 32

Connecting Points with Spanning Tree Tools

Introduction

This toolset and its scripts allow you to determine several variants of the Euclidean minimum
spanning tree (EMST) for point data within ArcMap, or from within Python programs. The
scripts are:

EMST_helper.py
This module contains the base code for producing the EMST. The Prim’s algorithm is used
and it was translated from Avenue code produced by William Huber (Quantitative Decisions).
Other functions allow for assembling the EMST in different ways or for obtaining other
information from it. For example, a treed version of the EMST can be produced whereby
branches of it emanate from a user-provided start node.

EMST_treed.py
A variant of the EMST script which allows for multiple EMSTs to be created for a space-
delimited list of origin node IDs. Alternately, points can be spatially allocated to the origin
nodes and a desire line connecting the input points to the origin node is created. The data
are radially sorted.

EMST.py
This module is specific to ArcMap and provides the necessary code to read point shapefiles
and produce the EMST as a point shapefile. This scripts imports EMST_helper.py,
arcpy_helper.py and groupPnts_helper.py as well as other base Python modules.

arcpy_helper.py
Provides utilities for working with the geoprocessor object.

groupPnts_helper
Allows for the grouping of points based upon an attribute. This enables the user to perform
a task on subsets returning an output for each set. In this case, a point dataset could be
subdivided based upon some class and the EMST determined for each one.

The toolbox enables one to select the point data and choose the type of EMST needed.
Examples follow.

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 1 of 32
The Spanning Tree toolset is shown to the right and the EMST tool’s
interface is shown below:

A layer of input points is required and an output polyline shapefile is required. The Grouping
field option allows one to produce individual EMSTs for groups of points based upon a text or
numeric attribute field. The Start node option is an option which allows the user to produce a
treed version of the EMST such that branches are formed which emanate outward from the
origin or trunk node. The input to this option is the feature ID number (FID) from the input
shapefile. This option cannot be used in conjunction with the Grouping field option.

The last option is a checkbox which allows you to produce a multipart and a singlepart EMST.
The various options and their outputs are shown in the follow sections.

Basic EMST

Euclidean minimum spanning trees can be used to


connect points so that each point is connected to
another point based upon the smallest distance
between point pairs. Also, no circuits are formed,
hence, the 3 nodes of a triangle would be
represented by two lines instead of three.

Consider the set of points in the figure to the right.


One can pretty well guess the connections that
need to be made to form the EMST. It is obvious
that point 4 connects with 8, and 8 with 9. Point 3
seems to be closer to 4 than 8. Points 1, 2 and 0
will also connect as will 5, 6 and 7. It is a little
difficult to see whether point 0 will connect with
point 4 or 5 and hence, whether 4 will connect with
5 either.

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 2 of 32
The EMST tool was used to derive the EMST for
the points shown to the right. It confirms that point
0 and 5 are closer together than 0 and 4. The
attribute table for this shapefile is shown below.

In this implementation, the input points are sorted lexicographically prior being used in the
EMST tool. There is no need to do this, but you can use it to your advantage if you want to see
the migration of the EMST from left to right and bottom to top. In the above example, you will
see that the first line (FID = 0) has a FromID of 8 and a ToID of 9. One would expect the EMST
to indicate the reverse and produce FromID - ToID pairs that are also sorted accordingly. This
isn’t the case, but a version exists that allows for line, and hence, point sorting.

Treed EMST

The EMST to the right is produced when you


specify a “trunk” point, or origin point within the
EMST tool. In this case, point 0 was chosen. The
branches that emanate from it are fairly obvious,
as well as the sub-branches within each branch.
The table is shown below

In this version, it is apparent that there are two branches as indicated in the GroupedBy column.

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 3 of 32
The first branch starts a point 0, passes through point 2 and ends at point 1 (see the FromID
and ToID information. The second branch starts a 0 and continues to point 5. At point 5, there
is a connection to point 4 and another to point 7. Point 4 extends to point 3 and also to point 9.

If point 5 is chosen as the principle node, you end up with the same EMST, but the number of
branches and their direction, are different, as shown in the two figures below.

Two other optional versions can be created, one which is a multipart shape (produced by a
dissolve) and the other which breaks up the multipart shape into its single part segments. The
latter can contain interconnected points between the terminal nodes, but it will generally lack
the directionality of the treed version. The tables for those are shown below. Note that the
FromID and ToID information is not present in either version.

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 4 of 32
The EMST can be determined for individual
groupings within a point file, as long as you have a
field that identifies which group the points belong
to. The figure to the right shows two EMSTs for
two groupings of points. It is assumed that the
point groupings are spatially separate, otherwise
there can be overlap in the outputs. A treed
version is produced in this option. If you want one
of the other versions, then you will have to perform
an attribute query to limit the selection to the
desired grouping.

Other Connections
The Connections tool allows the user to produce
multiple EMSTs given a space delimited list of
origin nodes. The origin nodes are then used to
partition the input data based upon minimum
euclidean distance to one of the origins. Once the
points are allocated to an origin, a treed version of
the EMST is derived. An example is shown to the
right for four origin nodes (points, 16, 27, 3 and
57).

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 5 of 32
The other output option is to choose the Lines to node option under the Output type
combobox. This produces desire lines which are sorted radially about/from the associated
origin node. The output is shown below.

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 6 of 32
Code documentation
'''
EMST.py

Purpose
Computes the minimum spanning tree of a set of points
using Prim's algorithm

Author
Dan Patterson
Dept of Geography and Environmental Studies
Carleton University, Ottawa, Canada
Dan_Patterson@carleton.ca
converted from Avenue code for ArcView 3.x

Original Prims code author


William A. Huber (Quantitative Decisions)
whuber@quantdec.com

Date March 2008


Modified March 2011 for ArcMap version 10

References
Derrick Wood, "Data Structures, Algorithms, & Performance"
(Addison-Wesley, 1993), Section 13.4.4. See also
Preparata & Shamos, "Computational Geometry" (Springer-Verlag,
1985), Section 6.1.

'''

#-----------------------------------------------------------------------------
def createPolyline(pnts):
'''creates a polyline from a list of points assign the X,Y and ID values
Points must be in the form x,y,id
'''
polyArray = arcpy.CreateObject("Array")
aPnt = arcpy.CreateObject("Point")
for aPair in pnts:
if isinstance(aPair, (list, tuple)):
aPnt.X = aPair[0]
aPnt.Y = aPair[1]
aPnt.ID = aPair[2]
#arcpy.AddMessage(str(aPnt.X) + " " + str(aPnt.Y) + " " + str(aPnt.id))
polyArray.add(aPnt)
return polyArray

def polyFromLines (out_FC, outType, SR, polylines, fieldsToAdd):


'''
Requires
out_FC output feature class name "c:/temp/myfile.shp"
outType output type "Polyline"
SR Spatial reference from input feature class
polylines a list of polylines (x,y,ID)
eg [ [10,10,1], [12,15,2], [7,3,3] ]
arcpy the Geoprocessor Object

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 7 of 32
Create the output filename and feature class, use the Spatial Reference
of the input feature class
'''
#import os, sys #required if used in other modules
full_name = os.path.split(out_FC)
out_folder = full_name[0].replace("\\","/")
outFName = full_name[1].replace(" ", "_")
outFullName = out_folder + "/" + outFName

try:
arcpy.CreateFeatureclass_management(out_folder, outFName, outType, "#",
"Disabled", "Disabled", SR)
arcpy.AddMessage("\n" + "Creating " + str(outFName) + "\n")
except:
arcpy.AddMessage("Failed to create feature class" + arcpy.GetMessages())
sys.exit()
for aField in fieldsToAdd:
arcpy.AddMessage("Adding field " + str(aField))
try:
arcpy.AddField_management(outFullName, aField[0], aField[1], aField[2],
aField[3], aField[4])
except:
arcpy.AddMessage("Failed to add field: " + str(aField))
#sys.exit()
#
try:
cur = arcpy.InsertCursor(out_FC)
except:
arcpy.AddMessage("failed to create cursor")
sys.exit()

for i in range(0,len(polylines)):
outShape = polylines[i][0] #the first is the polyline
aClass = polylines[i][1] #this is the grouping class
num_pnts = outShape.count
pnt1ID = outShape.getObject(0).ID #get the first id
pnt2ID = outShape.getObject(num_pnts - 1).ID #get the last id
feat = cur.newRow()
feat.shape = outShape
feat.FromID = pnt1ID
feat.ToID = pnt2ID
feat.GroupedBy = aClass
cur.insertRow(feat)
del cur

#-----------------------------------------------------------------------------
#import the modules and create arcpy
#
import sys, os, math
import arcpy
import arcpy_helper
import groupPnts_helper
import EMST_helper

arcpy.AddMessage("\n EMST, processing: using ArcMap 10")

toolboxes = ["Data Management Tools.tbx"]

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 8 of 32
arcpy, msg, passed = arcpy_helper.get_toolboxes(toolboxes, arcpy)
arcpy.AddMessage(msg)
if not passed:
arcpy.AddMessage("\n Exiting ..... \n")
del arcpy
sys.exit()

arcpy.env.overwriteOutput = True

desc = arcpy.Describe
in_FC = sys.argv[1]
group_field = sys.argv[2]

out_FC = sys.argv[3].replace("\\","/")

if sys.argv[4] != "#":
origin_node = int(sys.argv[4])
treed_version = True
else:
origin_node = 0
treed_version = False

if str(sys.argv[5]) == "true":
other_versions = True
else:
other_versions = False

full_name = os.path.split(out_FC)
out_folder = full_name[0].replace("\\", "/")

shape_Type= desc(in_FC).shapeType
shape_field = desc(in_FC).shapeFieldName
OIDField = desc(in_FC).OIDFieldName
fc = desc(in_FC).CatalogPath.replace("\\","/")
SR = desc(in_FC).spatialReference

if shape_Type != "Point":
arcpy.AddMessage("\nRequires a point file...bailing" + "\n")
sys.exit()
else:
arcpy.AddMessage("\nProcessing " + in_FC + " " + shape_Type)

#determine the grouping field type


arcpy.AddMessage("Grouping by: " + group_field)
fields = arcpy.ListFields(in_FC)

pntList = []
rows = arcpy.SearchCursor(in_FC)
if (shape_Type == "Point") and (group_field == "#"): #collect points
pnts=[]
for row in rows:
aShape = row.getValue(shape_field) #get the shape from the shape field
pnt = aShape.getPart()
XY = [pnt.X, pnt.Y] #get the X and Y
if XY not in pnts:
pnts.append(XY)
pntList.append(pnts)

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 9 of 32
aType = "None" #needed for treed version
elif (shape_Type == "Point") and (group_field != "#"):
theReturned = groupPnts_helper.groupPoints(group_field, in_FC, arcpy)
pntList = theReturned[0]
fldInfo = theReturned[1]
aName = fldInfo[0]; aType = fldInfo[1]; aPrec = fldInfo[2]
aScale = fldInfo[3]; aLeng = fldInfo[4]
valueList = theReturned[2]
theType = fldInfo[1]
#arcpy.AddMessage("pntList returned " + str(pntList))
else: #collect points for poly* features
for row in rows: #convert the shape to points
aShape = row.getValue(shape_field) #get the shape from the shape field
pnts = arcpy_helper.shapeToPoints(aShape, shape_Type, arcpy)
pntList.append(pnts)
aType = "None"
del rows

#perform a query to limit the points


rows = arcpy.SearchCursor(in_FC)
valueList = []
outList = []
if group_field == "#": #do all points as one group
arcpy.MakeFeatureLayer_management(in_FC, "TempLayer")
rows = arcpy.SearchCursor("TempLayer")
aType = "String"
aPrec = 10
aScale = 0
aLeng = 10
aVal = "None"
pntList = []
for row in rows:
aShape = row.shape
pnt = aShape.getPart()
pnts = [pnt.X, pnt.Y, row.getValue(OIDField), aVal]
if pnts not in pntList:
pntList.append(pnts)
else:
arcpy.AddMessage("Duplicate point ignored.")

primsResult = EMST_helper.prims(pntList) #run prim's algorithm


outList.append( [primsResult, "None"] )

else: #do points by groups


pntList = []
for row in rows:
aVal = row.getValue(group_field)
if aVal not in valueList:
valueList.append(aVal)
for aVal in valueList:
aVal = str(aVal)
queryVal = str(aVal)
if (not aVal.isdigit()) or (aType == "String"):
queryVal = "'"+aVal+"'"
whereClause = "%s = %s" % (group_field, queryVal)
arcpy.MakeFeatureLayer_management(in_FC, "TempLayer", whereClause)
rows = arcpy.SearchCursor("TempLayer")

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 10 of 32
#pntList = []
for row in rows:
aShape = row.shape
pnt = aShape.getPart()
pnts = [pnt.X, pnt.Y, row.getValue(OIDField),aVal]
if pnts not in pntList:
pntList.append(pnts)
else:
arcpy.AddMessage("duplicate point found")
pntList.append(pnts)

primsResult = EMST_helper.prims(pntList) #run prim's algorithm


outList.append( [primsResult, aVal] )
arcpy.AddMessage("\nPrims algorithm complete...")

#create the optional treed version


#check to see if the origin node is within the possible realm of shapes
#since that the FID field is used to identify nodes
#arcpy.AddMessage(str(pntList))

if treed_version:
pnt_dict = EMST_helper.pnts_to_dict(pntList)
if not(pnt_dict.has_key(origin_node)):
arcpy.AddMessage("Origin node is not in the list of FID numbers")
sys.exit()
from_to_list = EMST_helper.branches(primsResult)
tree = EMST_helper.form_tree(origin_node, from_to_list)
tree_branches = EMST_helper.connect_branches(origin_node, tree)
outList = []

for i in range(len(tree_branches)):
polyline_list = EMST_helper.tree_pnts(tree_branches[i], pnt_dict)
outList.insert( len(outList), [polyline_list, str(i)] )

#create the shapefile


#
polylines = []
for a_line in outList:
pnts = a_line[0]
aClass = a_line[1]
for aPair in pnts:
aPolyline = createPolyline(aPair)
polylines.append([aPolyline, aClass]) #pass on the polyline and class

if len(polylines) > 0:
# try:
if aType in ["Text", "String", "None", "AllPoints"]:
GroupBy = ["GroupedBy", "TEXT", aPrec, aScale, aLeng]
elif aType == "Integer":
GroupBy = ["GroupedBy", "LONG", "16", aScale, str(aLeng)]
fieldsToAdd = [["FromID", "LONG", "9", "#", "#"],
["ToID", "LONG", "9", "#", "#"],
GroupBy ]
arcpy.AddMessage("Fields to add: " + str(fieldsToAdd))
polyFromLines(out_FC, "Polyline", SR, polylines, fieldsToAdd)
# except:
# arcpy.AddMessage("Failed to create EMST: " + arcpy.GetMessages())

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 11 of 32
# sys.exit()
else:
arcpy.AddMessage("No shapes to create")

#
#Attempt to correct for geometry errors, there are some errors that aren't
trapped however.
try:
arcpy.RepairGeometry_management(out_FC)
arcpy.AddMessage("\n" + "Attempting to repair any geometry errors" + "\n")
except:
arcpy.AddMessage("Unable to repair geometry " + arcpy.GetMessages())
sys.exit()
#
#produce a dissolved and singlepart versions

if other_versions:
try:
outFName = full_name[1].replace(".shp", "") + "_mp.shp"
outFName2 = full_name[1].replace(".shp", "") + "_sp.shp"
dissolved = out_folder + "/" + outFName
dissolved2 = out_folder + "/" + outFName2
arcpy.AddMessage("Creating a dissolved EMST: " + dissolved)
arcpy.MakeFeatureLayer_management(out_FC,"EMST_dissolved")
if group_field != "#":
arcpy.Dissolve_management("EMST_dissolved", dissolved, "GroupedBy" )
else:
arcpy.Dissolve_management("EMST_dissolved", dissolved)
arcpy.RepairGeometry_management(dissolved)
arcpy.AddMessage("Creating a singlepart EMST: " + dissolved2)
arcpy.MultipartToSinglepart_management(dissolved,dissolved2)
arcpy.RepairGeometry_management(dissolved2)
arcpy.AddMessage("\nNOTE:\n" + \
"Two other EMST versions have also been created: \n\t" + \
dissolved + "\n\t" + dissolved2 + \
"\nYou will have to add these manually\n")
except:
arcpy.AddMessage("\n" + "Unable to created dissolved versions" + "\n")
arcpy.AddMessage(arcpy.GetMessages())

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 12 of 32
'''
EMST_treed.py

Purpose
Computes a spanning tree of a set of points using Prim's algorithm
for points that are connected

Author
Dan Patterson
Dept of Geography and Environmental Studies
Carleton University, Ottawa, Canada
Dan_Patterson@carleton.ca
converted from Avenue code for ArcView 3.x

Original code author


William A. Huber (Quantitative Decisions)
whuber@quantdec.com

Date July 2010


Modified March 2011 for ArcMap version 10

References
Derrick Wood, "Data Structures, Algorithms, & Performance"
(Addison-Wesley, 1993), Section 13.4.4. See also
Preparata & Shamos, "Computational Geometry" (Springer-Verlag,
1985), Section 6.1.

'''

#-----------------------------------------------------------------------------
def createPolyline(pnts):
'''creates a polyline from a list of points assign the X,Y and ID values
Points must be in the form x,y,id
'''
polyArray = arcpy.CreateObject("Array")
aPnt = arcpy.CreateObject("Point")
for aPair in pnts:
if isinstance(aPair, (list, tuple)):
aPnt.X = aPair[0]
aPnt.Y = aPair[1]
aPnt.ID = aPair[2]
#arcpy.AddMessage(str(aPnt.x) + " " + str(aPnt.y) + " " + str(aPnt.id))
polyArray.add(aPnt)
return polyArray

def polyFromLines (out_FC, outType, SR, polylines, fieldsToAdd):


'''
Requires
out_FC output feature class name "c:/temp/myfile.shp"
outType output type "Polyline"
SR Spatial reference from input feature class
polylines a list of polylines (x,y,ID)
eg [ [10,10,1], [12,15,2], [7,3,3] ]
arcpy the Geoprocessor Object
Create the output filename and feature class, use the Spatial Reference
of the input feature class
'''

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 13 of 32
#import os, sys #required if used in other modules
full_name = os.path.split(out_FC)
out_folder = full_name[0].replace("\\","/")
outFName = full_name[1].replace(" ", "_")
outFullName = out_folder + "/" + outFName
try:
arcpy.CreateFeatureclass_management(out_folder, outFName, outType, "#",
"Disabled", "Disabled", SR)
arcpy.AddMessage("\n" + "Creating " + str(outFName) + "\n")
except:
arcpy.AddMessage("Failed to create feature class" + arcpy.GetMessages())
sys.exit()
for aField in fieldsToAdd:
arcpy.AddMessage("adding field " + str(aField))
try:
arcpy.AddField_management(outFullName, aField[0], aField[1], aField[2],
aField[3], aField[4])
except:
arcpy.AddMessage("Failed to add fields: " + arcpy.GetMessages())
#sys.exit()
#
try:
cur = arcpy.InsertCursor(out_FC)
except:
arcpy.AddMessage("failed to create cursor")
sys.exit()

#anID=0
for i in range(0,len(polylines)):
outShape = polylines[i][0] #the first is the polyline
aClass = polylines[i][1] #this is the grouping class
num_pnts = outShape.count
pnt1ID = outShape.getObject(0).ID #get the first id
pnt2ID = outShape.getObject(num_pnts - 1).ID #get the last id
feat = cur.newRow()
feat.shape = outShape
feat.FromID = pnt1ID
feat.ToID = pnt2ID
feat.GroupedBy = aClass
cur.insertRow(feat)
del cur

#-----------------------------------------------------------------------------
#import the modules and create gp
#
import sys, os, math, string
import arcpy
import arcpy_helper
import groupPnts_helper
import EMST_helper

arcpy.AddMessage("\n EMST, processing: using ArcMap 10")

toolboxes = ["Data Management Tools.tbx"]


arcpy, msg, passed = arcpy_helper.get_toolboxes(toolboxes, arcpy)
arcpy.AddMessage(msg)
if not passed:

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 14 of 32
arcpy.AddMessage("\n Exiting ..... \n")
del arcpy
sys.exit()

arcpy.env.overriteOutput = True

desc = arcpy.Describe
in_FC = sys.argv[1]
out_FC = sys.argv[2].replace("\\","/")
input_nodes = string.split(sys.argv[3])
output_type = sys.argv[4]
treed_version = True

main_nodes = []
for i in input_nodes:
main_nodes.append(int(i))

full_name = os.path.split(out_FC)
out_folder = full_name[0].replace("\\", "/")

shape_Type = desc(in_FC).ShapeType
shape_field = desc(in_FC).shapeFieldName
OIDField = desc(in_FC).OIDFieldName
fc = desc(in_FC).CatalogPath.replace("\\","/")
SR = desc(in_FC).SpatialReference

if shape_Type != "Point":
arcpy.AddMessage("\n" + "Requires a point file...bailing" + "\n")
sys.exit()
else:
arcpy.AddMessage("\n" + "Processing " + in_FC + " " + shape_Type)

#perform a query to limit the points


rows = arcpy.SearchCursor(in_FC)

valueList = []
arcpy.MakeFeatureLayer_management(in_FC, "TempLayer")
rows = arcpy.SearchCursor("TempLayer")
aVal = "None"
pntList = []
node_list = []
for row in rows:
aShape = row.getValue(shape_field)
pnt = aShape.getPart()
pnt_vals = [pnt.X, pnt.Y, row.getValue(OIDField), aVal]
if pnt_vals[2] in main_nodes:
node_list.append(pnt_vals)
if pnt_vals not in pntList:
pntList.append(pnt_vals)
else:
arcpy.AddMessage("Duplicate point ignored.")

pnt_dict = EMST_helper.pnts_to_dict(pntList)
alloc_dict = EMST_helper.allocate(pntList, node_list)

counter = 0

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 15 of 32
outList = []
if output_type == "EMST":
for origin_node in alloc_dict.keys():
arcpy.AddMessage("EMST for point " + str(origin_node))
key_pnts = alloc_dict.get(origin_node)
primsResult = EMST_helper.prims(key_pnts)
from_to_list = EMST_helper.branches(primsResult)
tree = EMST_helper.form_tree(origin_node, from_to_list)
tree_branches = EMST_helper.connect_branches(origin_node, tree)

for i in range(len(tree_branches)):
polyline_list = EMST_helper.tree_pnts(tree_branches[i], pnt_dict)
outList.insert( len(outList), [polyline_list, str(origin_node)] )
counter += 1
else:
for node_data in node_list:
origin_node = node_data[2]
key_pnts = alloc_dict.get(origin_node)
arcpy.AddMessage("Radial lines for point " + str(origin_node))
spanResult = EMST_helper.sort_radial(key_pnts, node_data)
sorted_pnts = spanResult[0]
lines_to_key =[]
for i in sorted_pnts:
lines_to_key.append( [node_data, i] )
outList.append( [lines_to_key, origin_node] )

#create the shapefile


#
polylines = []
for a_line in outList:
pnts = a_line[0]
aClass = a_line[1]

for aPair in pnts:


aPolyline = createPolyline(aPair)
polylines.append([aPolyline, aClass]) #pass on the polyline and class

if len(polylines) > 0:
#arcpy.AddMessage("In type " + str(inType))
try:
GroupBy = ["GroupedBy", "LONG", "16", "#", "#"]
fieldsToAdd = [["FromID", "LONG", "9", "#", "#"], \
["ToID", "LONG", "9", "#", "#"], \
GroupBy ]
arcpy.AddMessage("Fields to add: " + str(fieldsToAdd))
polyFromLines(out_FC, "Polyline", SR, polylines, fieldsToAdd)
except:
arcpy.AddMessage("Failed to create EMST: " + arcpy.GetMessages())
sys.exit()
else:
arcpy.AddMessage("No shapes to create")

#Attempt to correct for geometry errors, there are some errors that aren't
trapped however.
try:
arcpy.RepairGeometry_management(out_FC)
arcpy.AddMessage("\n" + "Attempting to repair any geometry errors" + "\n")

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 16 of 32
except:
arcpy.AddMessage("Unable to repair geometry " + arcpy.GetMessages())
sys.exit()
#

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 17 of 32
'''
EMST_helper.py

Author
Dan Patterson
Dept of Geography and Environmental Studies
Carleton University, Ottawa, Canada
Dan_Patterson@carleton.ca
converted from Avenue code for ArcView 3.x

Original code author


William A. Huber (Quantitative Decisions)
whuber@quantdec.com

See EMST.py for further comments and original Prims algorithm implementation

Requires: Python 2.4.x or above

Purpose:

Form a tree from an Euclidean Minimum Spanning Tree (EMST)


See EMST.py for creating the EMST within ArcGIS

Date March 2008


Modified March 2011

Input forms
points pnts = [[ X, Y, ID, GroupedBy], ... [ X, Y, ID, GroupedBy]]
not the attributes are required by X,Y values are needed as a minimum
other attributes are simply ignored, but can be used in other applications

from_to_list A from-to-list is simply the ID number of two connecting


points without the geometry. This in essence forms a line
segment and the EMST connects these segments

Functions requiring points (pnts)


prim calculates the EMST, returns the edges/segments forming
the EMST
pnts_to_dict returns a dictionary whose keys are the IDs for
points in the form:
pnts = [[ X, Y, ID, GroupedBy], ... [ X, Y, ID, GroupedBy]]

Functions requiring a EMST result


branches generates the from_to_list, essentially the IDs of
the point pairs originating from the Prim analysis

Functions requiring a from_to_list


form_tree returns a tree version of the EMST, originating from
a start node and the from_to_list
make_connections called by form_tree
node_types returns the from_set, to_set, intersection set and
symmetrical difference set given the from_to_list

Functions requiring a tree


connect_branches returns a slightly different tree version of the
EMST whereby a node is chosen and all branches

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 18 of 32
emanating from this node are consolidated

'''

import sys
import math

def sort_radial(pnts, cent):


'''
Performs a radial sort about the center point, shifted to the origin
Returns two lists, the first is just the sorted points, the second
contains the sort angle as the first entry
'''
sorted_pnts =[]
out_pnts = []
for pnt in pnts:
dy = pnt[1] - cent[1]
dx = pnt[0] - cent[0]
p_angle = math.degrees( math.atan2(dy,dx) )
sorted_pnts.append([p_angle, pnt])
sorted_pnts.sort()
sorted_pnts.reverse()
for i in sorted_pnts:
out_pnts.append(i[1])
return [out_pnts, sorted_pnts]

def allocate(pnts, alloc_pnts):


'''
Returns the allocation of points in a list to allocation points based
upon the minimum distance. Points are in the format described in the
header.
'''
alloc_dict = {}
for i in alloc_pnts:
alloc_dict[i[2]] = []

for pnt in pnts:


min_dist = 10^150
for pnt_a in alloc_pnts:
dist = math.hypot( (pnt[0] - pnt_a[0]),(pnt[1] - pnt_a[1]) )
if dist < min_dist:
min_dist = dist
min_pnt = pnt_a[2]
alloc_list = alloc_dict.get(min_pnt)
alloc_list.append(pnt)
alloc_dict[min_pnt] = alloc_list
return alloc_dict

def prims(pnts):
'''Input pnts = [[ X, Y, ID, GroupedBy], ... [ X, Y, ID, GroupedBy]]
x,y coordinates
ID point ID
GroupdBy a value (numeric or test), or None
which allows you to group point sets

Returned: [[fromX, fromY, ID, GroupedBy], [toX, toY, ID, Groupedby],


distance]

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 19 of 32
The description below assumes that you are passing edges rather than points
for analysis. This would be the case if you wanted the EMST of a
Delauney triangulation

Prim's algorithm

Find the vertex pntmin of V with minimum distance d to the points of edges
in emst_edges. The first step is just a glorified search for the minimum
distance in closest_list.

Initialization:
closest_list represents the vertices not yet included in the minimum
spanning
tree (MST). Each element of the list is of the form [[v,u],d] where v is a
point
not in the tree, u is, and d = the distance from v to u.
emst_edges is the set of edges [v,u] comprising the MST.
'''
#Constants.
iEdge = 0
iEdgeLength = 1
null_pnt = None
null_number = None
emst_edges = [] # The edges, as they are added
closest_list = [] # The vertices, waiting to be added
for i in pnts:
pnt = [i[0],i[1],i[2],i[3]] # X, Y, ID and GroupedBy
closest_list.append([[pnt, null_pnt], null_number])
while (len(closest_list) > 0):
min_dist = null_number
min_id = 0
for i in range(0,len(closest_list)): # Test each remaining vertex
uv_dist = closest_list[i][iEdgeLength]
if ((min_dist == null_number) or ((uv_dist != None) and (min_dist >
uv_dist)) ):
min_dist = uv_dist
min_id = i
vx = closest_list[min_id] # Adjoin edge i to the list of edges.
lPtEdge = vx[iEdge]
lPtEdge.append(min_dist) # add the distance information (June 2010)
pntmin = lPtEdge[0]
ptUMin = lPtEdge[1]
if (ptUMin != None):
emst_edges.append(lPtEdge)
closest_list.pop(min_id) # Remove lPtEdge from V.
#This guarantees loop termination.
# Update the distances in closest_list.
# Vertices of closest_list must be compared to the new node, pntmin.
for vx in closest_list:
lPtEdge = vx[iEdge]
uv_dist = vx[iEdgeLength] # Distance from v to u
pnt = lPtEdge[0]
ptU = lPtEdge[1]
#
#Check the distance conditions Original,
xDistance = math.hypot(pntmin[0] - pnt[0], pntmin[1] - pnt[1])

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 20 of 32
if ((ptU == None) or (xDistance < uv_dist)):
lPtEdge[1] = pntmin
vx[iEdgeLength] = xDistance # Update information for this vertex (vx).
emst_edges.sort() #sort lexicographically, not needed but
useful
return emst_edges

def prims_connected(pnts, main_nodes):


'''
Variant of prims algorithm that allows for connected points
'''
#Constants.
must_connect = []
for i in range(1, len(main_nodes)):
must_connect.append([main_nodes[i-1], main_nodes[i]])

iEdge = 0
iEdgeLength = 1
null_pnt = None
null_number = None
emst_edges = [] # The edges, as they are added
closest_list = [] # The vertices, waiting to be added
for i in pnts:
pnt = [i[0],i[1],i[2],i[3]] # X, Y, ID and GroupedBy
closest_list.append([[pnt, null_pnt], null_number])
while (len(closest_list) > 0):
min_dist = null_number
min_id = 0
for i in range(0,len(closest_list)): # Test each remaining vertex
uv_dist = closest_list[i][iEdgeLength]
if ((min_dist == null_number) or ((uv_dist != None) and (min_dist >
uv_dist)) ):
min_dist = uv_dist
min_id = i
vx = closest_list[min_id] # Adjoin edge i to the list of edges.
lPtEdge = vx[iEdge]
lPtEdge.append(min_dist) # add the distance information (June 2010)
pntmin = lPtEdge[0]
ptUMin = lPtEdge[1]
if (ptUMin != None):
emst_edges.append(lPtEdge)
closest_list.pop(min_id) # Remove lPtEdge from V.
#This guarantees loop termination.
# Update the distances in closest_list.
# Vertices of closest_list must be compared to the new node, pntmin.
for vx in closest_list:
lPtEdge = vx[iEdge]
uv_dist = vx[iEdgeLength] # Distance from v to u
pnt = lPtEdge[0]
ptU = lPtEdge[1]
#
#Check the distance conditions Added July 2010
if [pntmin, pnt] in must_connect:
xDistance = -1
else:
xDistance = math.hypot(pntmin[0] - pnt[0], pntmin[1] - pnt[1])
#

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 21 of 32
if ((ptU == None) or (xDistance < uv_dist)):
lPtEdge[1] = pntmin
vx[iEdgeLength] = xDistance # Update information for this vertex (vx).
emst_edges.sort() #sort lexicographically, not needed but
useful
return emst_edges

def pnts_to_dict(pnts):
'''create a dictionary from pnt data in the form
pnts = [[ X, Y, ID, GroupedBy], ... [ X, Y, ID, GroupedBy]]
'''
dict = {}
for pnt in pnts:
dict[pnt[2]] = pnt
return dict

def branches(edges):
'''form the branches yielded from prim and returns a from_to_list'''
from_to_list = []
for a_pair in edges:
from_to_list.append( [a_pair[0][2], a_pair[1][2]] ) #a_pair[-1][2]] )
return from_to_list

def form_tree(node_num, from_to_list):


'''Form a tree from the connections within the EMST, beginning at
the parent node_num'''
max_loops = len(from_to_list) * 10
tree = []
connections, from_to_list = make_connections(node_num, from_to_list)
for twig in connections:
pair = [node_num, twig]
tree.append( pair)
keep_going = True
while keep_going:
for i in range(len(tree)):
node_num = tree[i][-1]
conn, from_to_list = make_connections(node_num, from_to_list)
if len(conn) > 1:
for twig in conn:
pair = [node_num, twig]
tree.append(pair)
elif len(conn) == 1:
tree[i].append(conn[0])
#a cludge to ensure loop termination
if len(from_to_list) == 0:
keep_going = False
return tree

def make_connections(node_num, from_to_list):


'''forms a tree from a node given a from_to list of connections and a
to from list of connections'''
to_remove = []
conn = []
for i in range(len(from_to_list)): #build the tree from a node number
from_to = from_to_list[i]
if node_num in from_to: #if node_num in from_to list, append 'to'
node

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 22 of 32
if from_to[0] == node_num:
conn.append(from_to[1])
else: #if node_num in to_from list, append 'from'
node
conn.append(from_to[0])
to_remove.append(from_to)
if len(to_remove) > 0:
for i in range(len(to_remove)):
from_to_list.remove(to_remove[i])
return conn, from_to_list

def node_types(from_to_list):
'''Requires: a list of from-to IDs
Returns: a list of intersections nodes (connects to at least 2 points)
or terminal nodes (only one node connects to it)
Uses sets to find the types, hence requires Python 2.4+
'''
from_id = []; to_id = []
from_to_list.sort()
for aPair in from_to_list:
from_id.append(aPair[0])
to_id.append(aPair[1])
nodes = [] #node list
from_set = set(from_id)
to_set = set(to_id)
inter_set = from_set.intersection(to_set)
sym_diff_set = from_set.symmetric_difference(to_set)
return from_set, to_set, inter_set, sym_diff_set

def pnt_distance(pnts, from_to_list):


'''point to point spacing given pairs of points in a from-to list'''
dist_list = []
for pair in from_to_list:
pnt_0_x = pnts[ pair[0] ][0]
pnt_0_y = pnts[ pair[0] ][1]
pnt_1_x = pnts[ pair[1] ][0]
pnt_1_y = pnts[ pair[1] ][1]
dist = math.hypot( (pnt_1_x - pnt_0_x),(pnt_1_y - pnt_0_y) )
dist_list.append( [pnt_0_x, pnt_0_y, pnt_1_x, pnt_1_y, dist] )
return dist_list

def tree_pnts(tree, pnt_dict):


'''construct a polyline point list from the tree'''
polyline_list = []
for a_branch in tree:
pnts = []
for a_pnt in a_branch:
pnts.append( pnt_dict[a_pnt] )
polyline_list.append(pnts)
return polyline_list

def connect_branches(node_num, tree):


'''connect the branches of a tree
main_branches the branches that connect to the main node (node_num)
'''
main_branches = []
for a_branch in tree:

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 23 of 32
if a_branch[0] == node_num:
tips = []
last_node = a_branch[-1]
a_branch = [a_branch]
main_branches.append(a_branch)
if last_node not in tips:
tips.append(last_node)
for a_stem in tree:
if a_stem[0] in tips:
a_branch.insert(len(a_branch), a_stem)
if a_stem[-1] not in tips:
tips.append(a_stem[-1])
return main_branches
#-------------------------------------------------------------
if __name__ == '__main__':
print "EMST_helper loaded"

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 24 of 32
'''
arcpy_helper.py
Author
Dan Patterson
Dept of Geography and Environmental Studies
Carleton University, Ottawa, Canada
Dan_Patterson@carleton.ca

Date August 18, 2010

Modified Dec 29, 2010

Purpose:
Helper functions, that use the geoprocessor created by arcpy

'''
#---------------------------------------------------------------
#required modules
import os, sys

def get_toolboxes(toolboxes, arcpy):


'''a list of toolboxes to add to the geoprocessor, arcpy'''
sub_folder = "ArcToolbox/Toolboxes/"
install_dir = arcpy.GetInstallInfo()['InstallDir'].replace("\\","/")
tbx_home = os.path.join(install_dir, sub_folder)
msg = ""
passed = True
for a_tbx in toolboxes:
try:
tbx = tbx_home + a_tbx
arcpy.AddToolbox(tbx)
msg = msg + "\n Adding toolbox: " + str(tbx)
except:
msg = msg + "\n The toolbox: " + str(tbx) + \
"\n could not be loaded. Check your toolbox path "
passed = False
return [arcpy, msg, passed]

def createFC (outFC, outType, SR, arcpy):


'''
Requires
outFC output feature class name. eg. "c:/temp/myfile.shp"
outType output type "Polygon" or "Polyline"
SR Spatial reference from input feature class
arcpy the geoprocessor object created in the source
'''
#Create the output filename and feature class, use the Spatial
#Reference of the input feature class
fullName = os.path.split(outFC)
outFolder = fullName[0].replace("\\","/")
outFName = fullName[1].replace(" ", "_")
outFullName = (outFolder + "/" + outFName)
#Create a shapefile
try:
arcpy.CreateFeatureclass_management(outFolder, outFName, outType, "",
"DISABLED", "DISABLED", SR)
arcpy.AddMessage("\n Creating " + str(outFullName) +

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 25 of 32
"\n Spatial reference: \n\t" + str(SR.Name))
except:
arcpy.AddMessage("\n Failed to create feature class" + "\n" +
arcpy.GetMessages())
sys.exit()
#
try:
cur = arcpy.InsertCursor(outFC)
except:
arcpy.AddMessage("\n Failed to create cursor")
del arcpy
sys.exit()
#-----------------------------------------------------------------------------
-
def pntXY(pnt):
'''Gets X,Y coordinates given a point object, returns a list'''
XY= [pnt.X, pnt.Y]
return XY
#---------------------------------------------------------------
def pntXYtoTuple(pnt):
'''Gets X,Y coordinates given a point object, returns a tuple'''
XY= (pnt.X, pnt.Y)
return XY
#-----------------------------------------------------------------------------
-
def polyFromPoints (outFC, outType, SR, outPntsList, theFields, arcpy):
'''
Requires
outFC output feature class name "c:/temp/myfile.shp"
outType output type "Polygon" or "Polyline"
SR Spatial reference from input feature class
outPntsList a list of lists of points
eg [ [10,10], [12,15], [7,3] ]
theFields the fields to add and their format
arcpy the Geoprocessor Object
'''
#Create the output filename and feature class, use the Spatial
#Reference of the input feature class
#import os, sys #required if used in other modules
fullName = os.path.split(outFC)
outFolder = fullName[0].replace("\\","/")
outFName = fullName[1].replace(" ", "_")
outFullName = (outFolder + "/" + outFName)
#
#Create a polygon shapefile
try:
arcpy.CreateFeatureclass_management(outFolder, outFName, outType, "",
"DISABLED", "DISABLED", SR)
arcpy.AddMessage("\n Creating " + str(outFullName) +
"\n Spatial reference: \n\t" + str(SR.Name))
except:
arcpy.AddMessage("\n Failed to create feature class")
sys.exit()
#
#Add any required fields fields
if len(theFields) != 0:
for i in range(0, len(theFields)):

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 26 of 32
aField = theFields[i]
try:
arcpy.AddField_management(outFullName, aField[0], aField[1],
aField[2], aField[3])
except:
arcpy.AddMessage("\n Cannot add field " + str(aField[0]) +
arcpy.GetMessages())
try:
insert_cursor = arcpy.InsertCursor(outFC)
except:
arcpy.AddMessage("\n Failed to create cursor")
del arcpy
sys.exit()
anID=0
polyArray = arcpy.CreateObject("Array")
aPnt = arcpy.CreateObject("Point")
for i in range(0,len(outPntsList)):
outShape = outPntsList[i][0]
for aPair in outShape:
aPnt.X = aPair[0]
aPnt.Y = aPair[1]
polyArray.add(aPnt)
feat = insert_cursor.newRow()
feat.shape = polyArray
feat.id = anID
if len(theFields) != 0:
for j in range(0, len(theFields)):
aField = theFields[j]
feat.setValue(aField[0],outPntsList[i][j+1])
insert_cursor.insertRow(feat)
polyArray.removeAll()
anID=anID+1
del polyArray
del aPnt
#-------------------------------------------------------------

def createPointFile (outFC, outType, SR, pnts, fieldsToAdd, arcpy):


'''Requires
outFC output feature class name "c:/temp/myfile.shp"
outType output type e.g. "Point"
SR Spatial reference from input feature class
pnts a list of lists of points eg.
[[pnt list 1],[pnt list 2]...[pnt list n]]
or [[pnt list 1]]
arcpy the Geoprocessor Object
Create the output filename and feature class, use the Spatial Reference
of the input feature class
'''
import os, sys #required if used in other modules
fullName = os.path.split(outFC)
outFolder = fullName[0].replace("\\","/")
outFName = fullName[1].replace(" ", "_")
outFullName = outFolder + "/" + outFName
try:
arcpy.CreateFeatureclass_management(outFolder, outFName, outType, "#",
"Disabled", "Disabled", SR)
arcpy.AddMessage( "\n" + "Creating " + str(outFName))

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 27 of 32
except:
arcpy.AddMessage( "Failed to create feature class" + arcpy.GetMessages())
sys.exit()
for aField in fieldsToAdd:
arcpy.AddMessage("Adding field " + str(aField))
try:
arcpy.AddField_management(outFullName, str(aField[0]), "LONG", "9")
except:
arcpy.AddMessage("Failed to add fields: " + arcpy.GetMessages())
sys.exit()
#
#Create the insert cursor
aPnt = arcpy.Point()
try:
cur = arcpy.InsertCursor(outFC)
except:
arcpy.AddMessage("failed to create cursor")
sys.exit()
anID=0
for i in range(0,len(pnts)):
aList = pnts[i]
aCount = 0
for j in range(len(aList)):
try:
aPnt.X = aList[j][0] #.x
aPnt.Y = aList[j][1] #.y
aPnt.ID = aCount
feat = cur.newRow()
feat.shape = aPnt
feat.setValue("ID", aCount)
#feat.SetValue("Group", anID)
cur.insertRow(feat)
aCount = aCount + 1
except:
arcpy.AddMessage("cannot create feature ")
anID = anID + 1
del cur

def shapeToPoints(a_shape,theType,arcpy):
'''
pnts = shapeToPoints(a_shape, shape type, geoprocessor)
Purpose: Converts a shape to points, the shape and its type
are passed by the calling script
Requires: def pntXY(pnt)
'''
outList=[]
part_num = 0
part_count = a_shape.partCount
if theType == "Multipoint": #Multipoints
while part_num < part_count:
pnt = a_shape.getPart(part_num)
XY = pntXY(pnt)
if XY not in outList:
outList.append(XY)
part_num += 1
else: #Poly* features

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 28 of 32
while part_num < part_count: #cycle through the parts
a_part = a_shape.getPart(part_num)
pnt = a_part.next()
while pnt: #cycle through the points
XY = pntXY(pnt)
if XY not in outList:
outList.append(XY)
pnt = a_part.next()
if not pnt: #null point check (rings/donuts)
pnt = a_part.next()
if pnt:
XY = pntXY(pnt)
if XY not in outList:
outList.append(XY)
part_num += 1
return outList
#
#-------------------------------------------------------------
if __name__ == '__main__':
try:
arcpy, gp_version = gp_create(10)
print "Geoprocessor created using: ", gp_version
except:
print "Geoprocessor cannot be created, check for ArcGIS"

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 29 of 32
'''groupPnts_Helper.py

Purpose: helper scripts to group points based upon an attribute

Author:
Dan Patterson
Dept of Geography and Environmental Studies
Carleton University, Ottawa, Canada
Dan_Patterson@carleton.ca

Date created: Jan 25 2006

Last modified: March 2011 updated for ArcGIS version 10


'''

def getPnts(rows):
'''Get unique points'''
pnts=[]
for row in rows:
aShape = row.shape
pnt = aShape.getPart()
XY = [pnt.X, pnt.Y] #get the X and Y
if XY not in pnts:
pnts.append(XY)
return pnts
#-----------------------------------------------------------------
def groupPoints(inField, inFC, arcpy):
'''group points based upon attributes in a field'''
groupedPoints = [] # list to hold grouped points
theFields = arcpy.ListFields(inFC)
inType = ""
desc = arcpy.Describe
OIDField = desc(inFC).OIDFieldName
OKFields = [OIDField]

arcpy.AddMessage("\n" + "Possible grouping fields" + "\n" + \


"%-10s %-10s %-6s %-6s %-6s %-6s " % \
("Field","Type","Prec","Scale","Length","Useable"))
for aField in theFields:
fType = aField.type
fScale = aField.scale
fName = aField.name
fPrec = aField.precision
fLeng = aField.length
if fName == inField:
inName = fName
inType = fType #used to determine field type later on
inPrec = fPrec
inScale = fScale
inLeng = fLeng
inFieldInfo = [inName, inType, inPrec, inScale, inLeng] #added May 2008
isOK = "Y"
if (fType == "String"):
OKFields.append(fName)
elif ((fScale == 0) and (fType !="Geometry")):
OKFields.append(fName)
else:

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 30 of 32
isOK = "N"
arcpy.AddMessage("%-10s %-10s %-6s %-6s %-6s %-6s" % \
(fName, fType, fPrec, fScale, fLeng, isOK))

#
if inField not in OKFields:
arcpy.AddMessage("The field " + inField + " is not an appropriate" + \
" field type. Terminating operation." + "\n")
del arcpy
sys.exit()
#
#Determine unique values in the selected field
arcpy.AddMessage(inField + " is being queried for unique values." + "\n")
valueList = []
rows = arcpy.SearchCursor(inFC)
aString = ""
aLen = 0; aFac = 1
for row in rows:
aVal = row.getValue(inField)
if aVal not in valueList:
valueList.append(aVal)
aLen = len(aString)
if aLen > 50 * aFac:
aString = aString + "\n"
aFac = aFac + 1
aString = aString + " " + str(aVal)
arcpy.AddMessage("Unique values: " + "\n" + aString)
#
#Do the actual work of producing the unique
aMax = 1
outVals = [] # a list to append valid output values
for aVal in valueList:
aMax = max(aMax,len(str(aVal)))
for aVal in valueList:
if (str(aVal).isdigit()) and (not inType == "String"):
fs = '"'+"%"+str(aMax)+"."+str(aMax)+'i"'
aSuffix = fs % aVal
aVal = str(aVal)
elif inType == "Double" and inScale == 0:
aSuffix = str(aVal).replace(".0","") ######
aVal = str(aVal).replace(".0","")
else:
aSuffix = str(aVal)
aVal = str(aVal)
try:
#Create a query and produce the file
if (not aVal.isdigit()) or (inType == "String"):
aVal = "'"+aVal+"'"
whereClause = "%s = %s" % (inField, aVal)
TempLayer = "TempLayer"
arcpy.MakeFeatureLayer_management(inFC, TempLayer, whereClause)
#
rowsNew = arcpy.SearchCursor("TempLayer")
pnts = getPnts(rowsNew)
if len(pnts) >= 3: #need 3 valid points for a convex hull
groupedPoints.append(pnts)
outVals.append(aVal)

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 31 of 32
except:
arcpy.AddMessage("Could not create temporary layer" + "\n")
whereClause = "%s = %s" % (inField, aVal)
del rows
del rowsNew
TempLayer = None
return [groupedPoints, inFieldInfo, outVals]

Spanning Tree Tools


Dan Patterson, Oct 2010: revised March 2011 Page 32 of 32

Vous aimerez peut-être aussi