This article as a PDF.
While fearing a real python might be justified, you shouldn't be intimidated by the Python language. Esri has embraced Python as the language that fulfills the needs of its user community.
Make sure the map document has the Title, Description, and Author fields filled out.
Programming with Python using the new ArcPy site-package in ArcGIS 10 makes GIS programming accessible for the average GIS professional. For longtime GIS users who yearn for the simpler days of Avenue (the scripting language used with ArcView 3.x), Python has some of the same attractive features: a manageable number of well-documented classes and functions, scripts that can be easily loaded into a document and executed, code shared as simple text files, and (perhaps best of all) no need to know what QueryInterface means. Python is a widely used, nonproprietary language, so learning Python can be beneficial for non-GIS applications.
To help you get started with Python, this tutorial will describe how to create a script that produces a simple report for the current map document. The generated report will contain information about all data frames and layers in the map. Optionally, it can list any layers that have broken data links and create a map package (*.mpk) for the document.
While the script itself may not be particularly exciting, the tutorial's primary goal is illustrating techniques commonly used when writing Python scripts. Specifically, the tutorial will show how to
Download MxdReport.py so you can reference it as you do the exercise.
There are several ways to run Python code in ArcGIS. The Python Window, new with ArcGIS 10, can be used to run single lines of Python code or load an entire script into a command line-type dialog. However, for authoring full scripts, such as the one described in this tutorial, a Python integrated development environment (IDE) is the best option. Several IDEs are available for Python. The Python IDLE editor, which is included with ArcGIS 10, will be used in this exercise.
Define the properties for the script by adding three parameters (Output Path, Package Map, and Track Broken Links) using the values shown in Table 1.
|Parameter Name||Data Type||Default Value|
Track Broken Links
Table 1: MxdReport.py script parameters
Python modules are files used to organize sets of additional functionality so your script can access it. The import statement is one way to bring a module into a script and make the functionality it defines available. At the top of the script window, type the following import statements:
import arcpy.mapping as mapping
The os and sys modules contain functions the script will need for working with files on disk. The ArcPy site-package will allow access to geoprocessing tools. The ArcPy mapping module provides functionality for working with the map document and the objects it contains.
Commonly, a script will need some input from the user to run. When creating a script, parameters can be defined to specify the information to be entered by the user. ArcGIS uses parameter information to create the necessary input controls. The order of parameters defined for the script is important, because parameter values are read from an ordered list of inputs. Add the following code to read user inputs:
outDir = arcpy.GetParameterAsText(0)
packageMap = arcpy.GetParameter(1)
checkBrokenLayers = arcpy.GetParameter(2)
GetParameterAsText reads the user input for the output file location (for example) as a text string. GetParameter reads user input and returns an object (e.g., Boolean).
When scripting in any environment, the current document is often the key object. Once a reference to the current document is obtained, the script can drill down into the additional objects it contains. A reference to the map document will provide access to the data frames, layers, and tables the map contains. Add the code below to get a reference to the current map document and store it in a variable called mxd.
mxd = mapping.MapDocument('Current')
The required parameter for the MapDocument function is either a path to a map document on disk or the keyword Current to get the map in which the script is executing.
The report generated by this script will be output as a simple text file to a location specified by the user. Add the code below to build the output file name for the report:
reportPath = outDir + '\\' + mxd.title + '.txt'
The + operator is used to concatenate strings in Python. The output report file will have the same name as the map, but with a .txt extension (e.g., C:\\Temp\\USA.mxd.txt).
Use the open function to open the file:
reportFile = open(reportPath, 'w')
The open function takes two arguments: the file name and the file mode. Valid file modes are w for write, r for read, and a for append. If the file exists, it will be overwritten. If it does not exist, it will be created. Add the line of code below to report the script's status to the user. This message will appear in the script's output window as it executes.
arcpy.AddMessage('Writing report to ' + reportPath)
The MapDocument object has several properties for getting basic information about the map. Create a variable to hold the report text and begin writing the report.
reportText = 'Title: ' + mxd.title + '\n'
reportText += 'Author: ' + mxd.author + '\n'
reportText += 'Description: ' + mxd.description + '\n'
reportText += '~~~~~~~~~~~~~~~~~~~~~~~~' + '\n'
The \n is an escape sequence used to generate a carriage return. The += combination is a shortcut for appending text to the end of the variable (e.g., reportText = reportText + "new text").
In all programming languages, the term branching refers to the ability to make decisions in the code. The most basic example is an IF/THEN statement, which will perform an action only if a specified condition is true. Define the following branching statement that checks if the user wants to create a map package:
Indentation is often used in scripts to make code more readable. In Python, indentation has a functional importance. Code that is indented under a branching statement indicates that the code should run in response to the condition being true. To check indentations, refer to MxdReport.py, downloaded from ArcUser Online. Add code to build the output path for the map package.
packagePath = outDir + '\\' + mxd.title.replace('.', '_') + '.mpk'
Build another branching statement that checks whether the output map package exists. If it does, add a message that informs the user the package will not be re-created:
arcpy.AddMessage('Map package already exists (' + packagePath + ')')
Any geoprocessing tool that is available from ArcToolbox may be executed programmatically using ArcPy. To create a map package, you will execute the PackageMap geoprocessing tool and pass in the required arguments. Add an ELSE section to the branching statement started above. Add a message to indicate that the map package is being created:
arcpy.AddMessage'(Creating map package' + packagePath + ')' )
Use ArcPy to call the PackageMap geoprocessing tool.
PackageMap_management requires the path to the map document and the path to the output package file.
In Python, you may wish to loop based on a condition (a WHILE loop) or over a collection of items (FOR loop). Use mapping.ListDataFrames to get a list of data frames from the map. Make sure to begin your code at the left edge of the editor (i.e., without indentation) to ensure it runs outside of the previous branching statement:
dataFrames = mapping.ListDataFrames(mxd, '')
The ListDataFrames function takes two arguments: a map document (or a path to one) and a wildcard string for filtering data frames based on name (e.g., La*). The function returns a Python list of data frames. Start a FOR loop to iterate over the data frames in the list:
for frame in dataFrames:
Add information about the data frame to reportText string. Like a branching statement, the code to execute inside a loop must be indented beneath the FOR statement.
reportText += '\nData Frame: ' + frame.name + '\n'
reportText += ('Spatial Reference: ' + frame.spatial Reference.name + '\n')
Inside the loop that iterates over data frame objects, a nested loop will iterate over the collection of layers inside each data frame. Add the code below to complete the nested loop of layer objects. Don't forget to indent this code beneath the parent loop.
layers = mapping.ListLayers(mxd, '', frame)
i = 0
for lyr in layers:
reportText += '\tLayer ' + (str(i) + ': ' + lyr. name + '\n')
i += 1
Similar to the ListDataFrames function, ListLayers returns a Python list object containing layer objects. The str function converts a value (e.g., integer) to a string.
Python's relative simplicity and power make it the scripting language of the future for ArcGIS.
Using Python to locate layers in the map that have missing data sources is easy. Rather than checking each layer individually, a single function—ListBrokenDataSources—can be used to return a Python list of broken layers. If the user has requested this information in the report, use ListBrokenDataSources to get a list of layers. The LEN function returns the number of items in a list.
arcpy.AddMessage('Checking for missing data sources')
brokenList = mapping.ListBrokenDataSources(mxd)
reportText += ('\nFound ' + str(len(brokenList)) + ' layers with missing
for broken in brokenList:
reportText += '\t- ' + broken.name + '\n'
At this point, all the text for the report is contained in the reportText variable. All that's needed now is to write this string to the output file that was created earlier. After writing the text stored in the reportText variable to the file, close it and delete the mxd variable using this code.
The script is now ready to run.
With the ArcPy site-package, Esri has integrated Python into ArcGIS 10. Python's relative simplicity and power make it the scripting language of the future for ArcGIS. For more information, contact Thad Tilton at firstname.lastname@example.org.
Thad Tilton is a senior GIS developer for Geographic Information Services, Inc.