Charming the Snake : Python Tips

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. 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 article will highlight a few basic techniques that are commonly required when writing

Python scripts for ArcGIS, such as how to:

  • Reference additional libraries (i.e., import functionality) for use in a script.
  • Accept user-provided arguments.
  • Get a reference to the current map document.
  • Create, open, and write to files.
  • Show messages that report the script’s progress.
  • Execute a geoprocessing tool.
  • Access objects in a map document (data frames, layers, tables).

Importing Additional Modules

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. To import a module, simply type an import statement at the top of the script window, like those shown below:

import os

import sys

import arcpy

import arcpy.mapping as mapping

This example shows some modules you may commonly work with. The os and sys modules contain functions for working with files on disk. The ArcPy site-package allows access to geoprocessing tools. The ArcPy mapping module provides functionality for working with the map document and the objects it contains.

Reading User Inputs

Commonly, a script will need some input from the user in order to run, and when creating a script, parameters can be defined to specify what information will be entered by the user. The order of parameters defined for the script is important, because parameter values are read from an ordered list of inputs. The following code illustrates how to read user inputs. Note that the

first parameter value is referenced by index position 0:

outDir = arcpy.GetParameterAsText(0)

packageMap = arcpy.GetParameter(1)

checkBrokenLayers = arcpy.GetParameter(2)

GetParameterAsText reads user input as a text string. GetParameter reads user input and returns an object (e.g., Boolean).

Getting a Reference to the Current Map

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. When scripting for ArcMap, a reference to the map document will provide access to the data frames, layers, and tables the map contains. The example below uses the MapDocument function 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.

Working with a File on Disk

Use the open function (imported in the os package) to open a file on disk:

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.

Use the write function to write information to a file (if it was opened in either write or append mode).

reportFile.write(reportText)

reportFile.close()

Make sure to close a file when you are done working with it.

Showing Status Messages as a Script Runs

Use the AddMessage function (from the ArcPy package) to display a message as your script runs. The code below produces a message that will appear in the script’s output window as it executes.

arcpy.AddMessage(‘Writing report to ‘ + reportPath)

Executing a Geoprocessing Tool

Any geoprocessing tool that is available from ArcToolbox may be executed programmatically using ArcPy. In fact, each tool is available as a function in ArcPy. Consult the ArcGIS documentation for more information regarding available geoprocessing tools. The example below will execute the Package Map geoprocessing tool (in the Data Management toolbox).

arcpy.PackageMap_management(mxdFilePath, packagePath)

PackageMap_management requires the path to the map document and the path to the output package file.

Get Objects in the Map (Data Frames and Layers, e.g.)

Use mapping.ListDataFrames to get a list of data frames from the map.

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. Similar to the ListDataFrames function, ListLayers returns a Python list object containing layer objects.

layers = mapping.ListLayers(mxd, ‘’, frame)

Conclusion

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 ttilton@gisinc.com.

Exporting Native Excel Files in Flex

Why is it that we developers always wait until the last minute to get around to the ‘Export to Excel’ requirement?  To be fair, all of the other requirements seem so much more interesting and we’ve exported to Excel 100 times before and can probably just copy some code from elsewhere.  So we put it on the back burner.

Then, of course, we end up running short on time and we just whip up some simple server-side script that converts a dataset to CSV format.  And sure, it meets the requirement, but it’s not pretty nor a native Excel file.  To boot, if you’re developing in Flex you likely have all of the data client-side already so making a trip back to the server is frivolous and time consuming.

Well, never fear – as3xls (link: http://code.google.com/p/as3xls/) is here.  This library was developed by some kind of Flex developer known only as Sigfrid3141 (link: http://code.google.com/u/Sigfrid3141/).  It can read and write the XLS format from your Flex code so that you can create a pretty, native Excel file and prompt the user to save that file all from your Flex application.

For one of my projects, I whipped up a utility class which has one static method – dataGridToExcel.  It takes a Flex DataGrid control and used the as3xls library to create an Excel file.  Feel free to borrow.  See the code below.

package com.gisinc.util
{
    import com.as3xls.xls.ExcelFile;
    import com.as3xls.xls.Sheet;
    import flash.net.FileReference;
    import flash.utils.ByteArray;
    import mx.collections.ICollectionView;
    import mx.collections.IViewCursor;
    import mx.controls.Alert;
    import mx.controls.DataGrid;
    import mx.controls.dataGridClasses.DataGridColumn;

    public class ExcelUtil
    {
        public static function dataGridToExcel(dataGrid:DataGrid, filename:String):void
        {
            var sheet:Sheet = new Sheet();
            sheet.resize((dataGrid.dataProvider as ICollectionView).length + 1, dataGrid.columns.length + 1);

            for(var i:int = 0; i < dataGrid.columns.length; i++) {
                sheet.setCell(0, i, (dataGrid.columns[i] as DataGridColumn).headerText);
            }

            var cursor:IViewCursor = dataGrid.dataProvider.createCursor();
            var rowCount:int = 1;

            while(!cursor.afterLast)
            {
                for(var j:int = 0; j < dataGrid.columns.length; j++)
                {
                    var col:DataGridColumn = dataGrid.columns[j] as DataGridColumn;
                    sheet.setCell(rowCount, j, col.itemToLabel(cursor.current));
                }
                rowCount++;
                cursor.moveNext();
            }

            var xls:ExcelFile = new ExcelFile();
            xls.sheets.addItem(sheet);

            var bytes:ByteArray = xls.saveToByteArray();
            var fileReference:FileReference = new FileReference();
            fileReference.save(bytes, filename);
        }
    }
}