Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
ArcGIS Geoprocessing
Advanced Scripting With Python
Corey Tucker
Nathan Warmerdam
Workshop Outline
• Review of scripting languages
– What is supported? What is recommended? Why?
• Data Access with cursors
– Review types and options
– Working with feature geometry
• Creating and using objects for parameter values
• How to create a script tool
• Making scripts more efficient
– Use of layers and table views
– Calling models
• Effective Error Handling
• Summary
Scripting Languages
• Many to choose from for geoprocessing tasks
–
–
–
–
–
Python
VBScript
JScript
Perl
Others
• Any language that supports COM IDispatch may
be used
• Python is the most commonly used by our users
and is what is most commonly documented
Scripting Languages
Python
• Why is Python recommended by ESRI
–
–
–
–
–
–
–
–
It is free!
Established user community
Simple when it needs to be
Easy to maintain
Scalable
Cross platform (windows, UNIX, Linux)
Many IDE’s to choose from
Supports object-oriented and modular designs
Scripting Languages
Python
• What version is supported?
– ArcGIS installs version 2.1, but all versions from 2.1
up to 2.4.1 are supported
• Why 2.1?
– Due to installation problems of PythonWin for later
versions of Python, ESRI had to ship version 2.1.
• How can I upgrade my version of Python
– Download install for 2.4.1
– Download PythonWin for 2.4.1
– Read Knowledge Base document #26872 from
support.esri.com
ArcGIS 9.2
Bulletin
• A native Python module for ArcGIS will be
included
–
–
–
–
Based on version 2.4.1
Eliminates need for PythonWin
Allows better error messaging
Cross platform support
• Can be used to run scripts on Unix and Linux that have a 9.2
ArcGIS Engine installation
– 9.0 and 9.1 scripts will just work. Older Dispatch
methodology will still be supported.
Scripting Documentation
and Samples
• Writing Geoprocessing Scripts with ArcGIS
– PDF in Documentation Library
– Explanation of methods and samples
• ArcGIS Online Help
– Same content as PDF
– Specific help and samples for all of the
geoprocessor’s methods and properties
• Geoprocessing Programming Guide
– Logical layout of scripting objects with their methods
and properties
– Quick Reference
Section 1: Cursors
Accessing Data
with Cursors
• Geoprocessing workflows commonly require record by record
access of field values
– Including the geometry field
• This is done using an object that points to a record in a table
or feature class called a cursor
• Examples
– Using a field value in an logical expression
if row.soiltype == “loam”:
row.group = 2
– Moving values from one table or feature class to another
if row1.parcelid == row2.parcelid:
row1.owner = row2.owner
– Accessing properties of a feature’s geometry
print row.shape.FirstPoint
Accessing Data
with Cursors
• There are three types of cursors
– Search Cursor
• Read-only access
– Update Cursor
• Read/Write/Delete access but no new records
– Insert Cursor
• Read/Write access with capability of creating new records
Accessing Data
with a Search Cursor
• A row object is returned from the search cursor
object
• Fields are accessed as properties of the row
object
• Use the row object’s GetValue and SetValue
methods if your field name is a variable
• Destroy the row and cursor objects to remove
read locks on the data source
Accessing Data
with a Search Cursor
from win32com.client import Dispatch
gp = Dispatch("esriGeoprocessing.gpDispatch.1")
rows = gp.SearchCursor("D:/St_Johns/data.mdb/roads")
row = rows.Next()
# Print concatenated values of road name and road type
while row:
print row.name + row.GetValue("type")
row = rows.Next()
# Delete the row and cursor objects so no locks remain
del row
del rows
Accessing Data
with Cursors
• A where clause may be used to limit the records
returned by the cursor
– Same as defining a definition query on a layer
from win32com.client import Dispatch
gp = Dispatch("esriGeoprocessing.gpDispatch.1")
rows = gp.SearchCursor("D:/St_Johns/data.mdb/roads",
“[neighborhood] = "Shea_Heights")
row = rows.Next()
# Print concatenated values of road name and road type
while row:
print row.name + row.GetValue("type")
row = rows.Next()
del row
del rows
Reading Feature
Geometry
• You must understand the hierarchy for geometry in order
to use it
– A feature class is made of features
– A feature is made of parts
– A part is made of points
• In Python terms
– A single part feature looks like this
[pnt, pnt, pnt]
– A multipart polygon feature looks like this
[[pnt, pnt, pnt],[pnt, pnt, pnt]]
– A single part polygon feature with a hole (inner ring) looks like
[[pnt, pnt, pnt, ,pnt, pnt, pnt]]
Reading Feature
Geometry
• A null point is used as a separator between rings (holes)
in a polygon part
• Use the PartCount property to get the number of parts
for a feature
• Use the GetPart method to retrieve the desired part
# Reading lines
x = 0
while x < feat.PartCount:
roadArray = feat.GetPart(x)
pnt = roadArray.Next()
while pnt:
print pnt.x + "," + pnt.y
pnt = RoadArray.Next()
x = x + 1
Reading Feature
Geometry
• Features may be projected on-the-fly to another
coordinate system using the Spatial Reference
parameter
• Create the Spatial Reference by describing another
dataset
# Describe features class with a GCS
desc = gp.Describe("D:/data.mdb/geo_roads")
# Create search cursor, using GCS spatial reference
rows = GP.SearchCursor("D:/data.mdb/roads","",
desc.SpatialReference)
row = rows.Next()
Demo 1 – Reading Feature Geometry
Reading Feature
Geometry - Tips
• Use field values instead of the properties of the
geometry object if speed is really important
– Length
– Area
• If you want the extent or centroid of a complex
feature try creating simple features in a new
feature class
– Features to Point
– Feature Envelope to Polygon
• Using fields or simple geometry is faster that
querying the geometry object of a complex
feature
Writing Feature
Geometry
• Insert cursors must be used to create new
features
rows = GP.InsertCursor("D:/data.mdb/roads“)
row = rows.NewRow()
• Use the Point and Array objects to create
feature parts
• A part may be used to set a geometry field
– A multipart feature is an array containing other
arrays, where each array is a part
Writing Feature
Geometry
# Open an insert cursor for the feature class
cur = GP.InsertCursor(fcname)
# Create the array and point objects needed to create a feature
lineArray = GP.CreateObject("Array")
pnt = GP.CreateObject("Point")
# Add two points to the array
pnt.x = 358331
pnt.y = 5273193
lineArray.Add(pnt)
pnt.x = 358337
pnt.y = 5272830
lineArray.Add(pnt)
# Create a new row, or feature, in the feature class
feat = cur.NewRow()
# Set the geometry of the new feature to the array of points
feat.shape = lineArray
# Insert the feature
cur.InsertRow(feat)
Writing Feature
Geometry
• The geoprocessor checks the validity of the
geometry before it is inserted
– Problems such as invalid ring order or ring orientation
are corrected automatically
– Uses the same process found in the Check and
Repair Geometry tools
• Writing features requires an exclusive schema
lock on the feature class
– Use the TestSchemaLock method to see if the data is
being used by another process
ArcGIS 9.2
Bulletin
• Cursor performance will be FASTER!
– Much faster for Update operations
• New option to limit the returned fields on a row
• New option to sort the rows on a field or set of
fields
• 9.0 and 9.1 scripts will just work
• Speed enhancements will be included in Service
Pack 1 for ArcGIS 9.1
Section 2: Complex Parameters
Tools and Parameters
• Each geoprocessing tool has a collection of
parameter values
• Parameters define how the tool will work
Using Objects for
Parameters
• Most tool parameters are easy to define using a
string or a number, such as a data path or buffer
distance
• Some parameters are more complex and have
complicated text string representations,
– spatial reference or field mapping
• Instead of using text strings, use objects
Using Objects for
Parameters
• Objects either created directly by
– The geoprocessor’s CreateObject method
– Another object, such as the descriptive object created
by the Describe method
– A tool, such as Create Spatial Reference
Using Objects for
Parameters
• Creating a geodatabase feature dataset
from win32com.client import Dispatch
gp = Dispatch("esriGeoprocessing.GPDispatch.1")
# Describe a dataset that has the desired SR
desc = gp.Describe("D:/St_johns/city.mdb/city_boundary")
# Create the FDS using the describe object's SR Object
gp.CreateFeatureDataset("D:/St_johns/city.mdb“,"NewFDS",
desc.SpatialReference)
SR = Spatial Reference
Using Objects for
Parameters
• Value Tables
– Used to define any tool parameter that accepts more
than one value (e.g. Merge)
– Multivalue parameters may be expressed as
• A string ("value1;value2;value3")
• As a Value Table
– Use LoadFromString method to load a multivalue
strting that may be passed as a script argument
– Use ExportFromString to create an output argument
value
• Useful for script tools
Using Objects for
Parameters
• Overlay tools, such as Union and Intersect use
Value Tables with multiple columns
– Difficult to parse multivalue string when more than
one column is used
("D:/data/new roads" 1;D:/data/soils 2)
• Value Tables with multiple columns are easy to
navigate
Section 3: Script Tools
Creating Tools
from Scripts
• Why?
– The script is generic and can be used with other data
• Script can use arguments from the user
– You want to use a script in ModelBuilder
• Incorporate another system with a script wrapper or do
branching
– You want to easily share your script
• Not everyone knows how to run a stand-alone script
• Puts a familiar face on your work
Creating Tools
from Scripts
• Step 1: Create argument variables
– Can use sys.argv[ ], but this is subject to windows
limitations (1024 characters)
– Should use GetParameterAsText, especially with
multivalue parameters
Creating Tools
from Scripts
• Step 2: Messaging
– Return informative messages during execution of the
script
– Return error messages when a problem arises
Creating Tools
from Scripts
• Step 3: Add the script to a toolbox
– Give the tool a name, label and description
– Set the tool source and use relative paths option if
you plan on sharing the tool
– Define the parameters that will correspond to your
script
Creating Tools
from Scripts
• Step 3: Defining Parameters
– Parameters have several properties
•
•
•
•
•
•
•
Name: What you see on the dialog and on the command line.
Type: Is it required, optional or derived?
Direction: Is the data being used (input) or created (output)?
Multivalue: Do you want a list of values or just one?
Default: Is there a default value?
Environment: Does an environment provide a default value?
Domain: Do you want to provide a choice or limit input
values?
• Dependency: Does this parameter depend on another?
Creating Tools
from Scripts
• Step 3: Derived Parameters
– All tools that will be used in ModelBuilder should have
an output
– If the script updates an input dataset, create a derived
parameter and set its dependency to the input
parameter
Value
Creating Tools
from Scripts
• Step 3: Parameter Dependency
– Some parameter types have built-in behavior when
there is a parameter dependency
• Fields with an Input table or feature class
– Fields will be populated automatically in the dialog
• Derived parameter with an input parameter
– The derived parameter value will automatically be set to the
value of the input parameter it depends upon
Demo 2: Creating A Script Tool
Creating Tools
from Scripts
• AML is a supported source for script tools
– Need to change the default behavior of an AML to
support this
• By default it must execute with arguments when opened
• Use the RegisterAMLAsExecutable registry file
to make this change
– File is in the ArcGIS\ArcToolbox\Scripts folder
• Any ArcInfo workstation module is supported
– AML must start in the Arc module and then call other
modules
– Display windows and form menus are supported
Section 3: Tips for Efficiency
Efficiency Tips
• When working with selections, use layers and
views instead of using the Select tool
– Layers and views are in memory and avoid costs of
writing to disk
• Use Make Feature Layer, Make Raster Layer or
Make Table View
• Use Select By Attribute to update the selection
or provide a where clause when creating the
layer or view
Efficiency Tips
• Call models from your scripts
– Instead of rewriting a model as a script, reference the
model’s toolbox and call it as a tool
– Simplifies code
from win32com.client import Dispatch
gp = Dispatch("esriGeoprocessing.gpDispatch.1")
# Add custom toolbox
gp.AddToolbox("D:/Data/St_Johns/MyTools.tbx")
gp.MyRoadsModel("D:/Data/St_Johns/urban_roads",100,
"C:/temp/results")
Efficiency Tips
• Use Python Lists and Dictionaries for frequent
access of attributes
– Instead of reading through a table multiple times with
a cursor, read it once and load the values into
memory
– Use a list for an ordered collection of values
– Use a dictionary if you have an unordered collection
of values and want to access values using a key
• Great for working with coordinates
– Many examples in the source scripts of the Spatial
Statistics tools
Section 4: Error Handling
Error Handling
• The Geoprocessor is just another COM Dispatch
object to Python, or any other language
– Error messages are less than helpful
• Tool messages must be retrieved from the
geoprocessor
• Scripts must add error handling routines to catch
errors and return tool messages
Error Handling
• Non-tool methods on the Geoprocessor do not
return error messages
– Cursors, Creating Lists, Describe, etc
• Use the Raise statement to trigger specific
exceptions
– Especially useful when using tools and native
methods together
– Provides more meaningful context for messages
Error Handling
try:
# Get the input feature class and make sure it contains polygons
input = sys.argv[1]
dsc = gp.Describe(input)
if dsc.ShapeType != "polygon": raise "ShapeError"
# Get the new field name
fieldname = sys.argv[2]
# Make sure shape_length and shape_area fields exist
if gp.ListFields(input,"Shape_area").Next() and \
gp.ListFields(input,"Shape_length").Next():
# Add the new field and calculate the value
gp.AddField(input, fieldname, "double")
gp.CalculateField(input,fieldname,
"[Shape_area] / [Shape_length]")
else:
raise "FieldError"
except "ShapeError":
print "Input does not contain polygons"
except "FieldError":
print "Input does not shape area and length fields"
except:
print gp.GetMessages(2)
Error Handling
• Use the sys module to access python syntax
errors
– Useful when using exec or eval functions
– Must import the sys module
except:
msgs = gp.GetMessages()
if msgs:
AddMsgAndPrint(msgs,2)
value = sys.exc_info()[1]
AddMsgAndPrint(value.msg + ": " + value.text ,2)
Demo 3: Error Handling
Additional support
• For additional information about geoprocessing including service
pack information, knowledge base articles, and recent information
about issues go to:
http://support.esri.com/geoprocessing
Additional technical sessions
• ArcGIS Geoprocessing: Introduction to ModelBuilder
Wed 3:30 PM Room: 6E
• ArcGIS Geoprocessing: Advanced ModelBuilder
Thu 8:30 AM
• ArcGIS Geoprocessing: An Introduction
Room: 6E
Wed 1:30 PM Room: 6E
• ArcGIS Geoprocessing: Developing Geoprocessing
tools with ArcObjects
Thu 10:30 AM Room: 6E
• ArcGIS Geoprocessing: Using Spatial Statistics in
ArcGIS
Thu 1:30 PM
Room: 8
Thu 3:30 PM
Room: 5-B
• ArcGIS Extension: 3D Analyst Geoprocessing Tools
Island demo’s & Demo Theatre sessions
Island Demo’s
• Working with Layers and Table Views in Geoprocessing
Wed 4:00 -4:30pm
• How to convert pGDB feature classes to .shp in a model
Thu 11:30 – 12noon
Demo theatre sessions
•
How to use the Geoprocessing Environment Settings
T1 - Tue 10:30 – 11:15am
T1 - Wed 1:30 – 2:15pm
•
Using Spatial Statistics for Crime Analysis
T1 - Thu 9 -10am
•
Geoprocessing Tool Documentation and Metadata
T1 - Thu 11:15 - 12noon
Thank you!
Please fill out your survey form
Questions?