To this point, we've talked about automating geoprocessing tools, updating GIS data, and reading text files. However, we've not covered anything about working with an Esri map document. There are many tasks that can be performed on a map document that are well-suited for automation. These include:
- Finding and replacing text in a map or series of maps. For example, a copyright notice for 2015 becomes 2016.
- Repairing layers that are referencing data sources using the wrong paths. For example, your map was sitting on a computer where all the data was in C:\data and now it is on a computer where all the data is in D:\myfolder\mydata.
- Printing a series of maps or data frames.
- Exporting a series of maps to PDF and joining them to create a "map book."
- Making a series of maps available to others on ArcGIS Server.
Esri map documents are binary files, meaning they can't be easily read and parsed using the techniques we covered earlier in this lesson. Until very recently the only way to automate anything with a map document was to use ArcObjects, which is somewhat challenging for beginners and requires using a language other than Python. With the release of ArcGIS 10.0, Esri added a Python module for automating common tasks with map documents.
The arcpy.mapping module
arcpy.mapping is a module you can use in your scripts to work with map documents. Please take a detour at this point to read the Esri Introduction to arcpy.mapping.
The most important object in this module is MapDocument. This tells your script which map you'll be working with. You can get a MapDocument by referencing a path, like this:
mxd = arcpy.mapping.MapDocument(r"C:\data\Alabama\UtilityNetwork.mxd")
Notice the use of r in the line above to denote a string literal. In other words, if you include r right before you begin you're string, it's safe to use reserved characters like the single backslash \. I've done it here because you'll see it in a lot of the Esri examples with arcpy.mapping.
Instead of directly using a string path, you could alternatively put a variable holding the path. This would be useful if you were iterating through all the map documents in a folder using a loop, or if you previously obtained the path in your script using something like arcpy.GetParameterAsText().
It can be convenient to work with arcpy.mapping in the Python window in ArcMap. In this case, you do not have to put the path to the MXD. There's a special keyword "CURRENT" that you can use to get a reference to the currently-open MXD.
mxd = arcpy.mapping.MapDocument("CURRENT")
Once you get a MapDocument, then you do something with it. Most of the functions in arcpy.mapping take a MapDocument object as a parameter. Let's look at this first script from the Esri help topic linked above and scrutinize what is going on. I've added comments to each line.
# Create a MapDocument object referencing the MXD you want to update mxd = arcpy.mapping.MapDocument(r"C:\GIS\TownCenter_2015.mxd") # Loop through each text element in the map document for textElement in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT"): # Check if the text element contains the out of date text if textElement.text == "GIS Services Division 2015": # If out of date text is found, replace it with the new text textElement.text = "GIS Services Division 2016" # Export the updated map to a PDF arcpy.mapping.ExportToPDF(mxd, r"C:\GIS\TownCenterUpdate_2016.pdf") # Clean up the MapDocument object by deleting it del mxd
The first line in the above example gets a MapDocument object referencing C:\GIS\TownCenter_2014.mxd. The example then employs two functions from arcpy.mapping. The first is ListLayoutElements. Notice that the parameters for this function are a MapDocument and the type of layout element you want to get back, in this case, "TEXT_ELEMENT". (Examine the documentation for List Layout Elements to understand the other types of elements you can get back.)
The function returns a Python list of TextElement objects representing all the text elements in the map document. You know what to do if you want to manipulate every item in a Python list. In this case, the example uses a for loop to check the TextElement.text property of each element. This property is readable and writeable, meaning if you want to set some new text, you can do so by simply using the equals sign assignment operator as in textElement.text = "GIS Services Division 2016"
The ExportToPDF function is very simple in this script. It takes a MapDocument and the path of the output PDF as parameters. If you look at the documentation for ExportToPDF, you'll notice a lot of other optional parameters for exporting PDFs, such as whether to embed fonts, that are just left as defaults in this example.
The best way to learn arcpy.mapping is to try to use it. Because of its simple, "one-line-fix" nature, it's a good place to practice your Python. It's also a good way to get used to the Python window in ArcMap, because you can immediately see the results of your actions.
Although there is no arcpy.mapping component to this lesson's project, you're welcome to use it in your final project. If you've already submitted your final project proposal, you can amend it to use arcpy.mapping by e-mailing and obtaining approval from the instructors. If you use arcpy.mapping in your final project, you should attempt to incorporate several of the functions or mix it with other Python functionality you've learned, making something more complex than the "one line fix" type of script I mentioned above.
By now you'll probably have experienced the reality that your code does not always run as expected on the first try. Before you start running arcpy.mapping commands on your production MXDs, I suggest making backup copies.
Here are a few additional places where you can find excellent help on learning arcpy.mapping: