Automating Regional Data Integration with Python & ArcPy (Heather Widlund)
ArcPy Mapping Module · 2 018v0000006s000000 ArcPy Mapping Module Jake K. Carr. Apply a De nition...
Transcript of ArcPy Mapping Module · 2 018v0000006s000000 ArcPy Mapping Module Jake K. Carr. Apply a De nition...
ArcPy Mapping Module
GIS 5222
Jake K. Carr
Week 9
ArcPy Mapping Module Jake K. Carr
Working with Map Files
The Arcpy Mapping Module allows us to automate a lot of map(.mxd) processing tasks.
The three ArcPy Mapping objects that we deal with are:
I Map Document (.mxd) Objects
I Data Frame Objects
I Layer Objects
Some of these automating capabilities can be very powerful.
ArcPy Mapping Module Jake K. Carr
Map Document Objects
Map Documents have a .mxd extension (obvious).
We access/open .mxd with the MapDocument function in one oftwo ways:
import arcpy
arcpy.env.workspace = r"C:\ Lectures\Lecture 9\Maps"
# Access Currently Open Map Document
myMXD = arcpy.mapping.MapDocument("Current")
OR
import arcpy
arcpy.env.workspace = r"C:\ Lectures\Lecture 9\Maps"
# Access Map Document and Change Some Properties
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
ArcPy Mapping Module Jake K. Carr
“Current” Map Documents
We will reserve the use of accessing the “Current” map documentwhen we are modifying a map document inside of a Python scripttool:
myMXD = arcpy.mapping.MapDocument("Current")
If we try to use the “Current” map document and there is no mapdocument open then ArcPy/Python won’t run subsequent lines ofcode.
This is the option that we will prefer when our script tool producessome type of output and we want to add it to the map that we arerunning the script tool in.
ArcPy Mapping Module Jake K. Carr
Non-opened Map Documents
If we want to operate on a map document outside of a script toolthen we will have to specify the full path directory of the mapdocument:
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
Once we have created this map document object (called myMXDhere) we can set some properties of Train Stations.mxd.
Open Train Stations.mxd and see what properties are set.
ArcPy Mapping Module Jake K. Carr
Set Some Map Document Properties
We will set the map document author, the map document title, tellArcMap to store relative path names and create a thumbnail of themap in ArcCatalog:
import arcpy
arcpy.env.workspace = r"C:\ Lectures\Lecture 9\Maps"
# Access Map Document and Change Some Properties
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
myMXD.author = "Jake K. Carr"
myMXD.title = "Our New Title"
myMXD.relativePaths = True
myMXD.makeThumbnail ()
# Save Those Changes
myMXD.save()
NOTE the use of the save() method here ⇒ It is necessary inorder to actually save these changes!
ArcPy Mapping Module Jake K. Carr
Finding All Map Documents
What if we have 100 map documents in a folder somewhere andwe want to assign some property to all of them?
We’re going to need some more firepower!
Namely, we will use the os and glob modules - which are both basePython modules (nice).
The os module gives you a lot of functionality to access things onyour operating system - like path names/folder directories.
ArcPy Mapping Module Jake K. Carr
Finding All Map Documents
The glob module has two functions - which allow you to access (orcreate lists of) the files in a specified path name/folder directory.
We will use these two modules in conjunction with a WILDCARDto look for all of the .mxd files in our workspace folder.
We’ll make a list of all map documents, iterate through that list,and then set the AUTHOR property on all of them.
We’ll attribute my email address as the Author identifier on all ofthese maps.
ArcPy Mapping Module Jake K. Carr
BOOM!
We use the chdir function from the os module to ‘point’ Python tothe same directory/folder as our environment workspace.
We then use the glob function from the glob module to make a listof all files with an .mxd extension in that directory/folder:
# Get a List of Map Documents
import os
import glob
import arcpy
arcpy.env.workspace = r"C:\ Lectures\Lecture 9\Maps"
os.chdir(arcpy.env.workspace)
lstMxds = glob.glob("*.mxd")
for mpdoc in lstMxds:
myMXD = arcpy.mapping.MapDocument(mpdoc)
myMXD.author = "carr .526 @osu.edu"
myMXD.save()
print mpdoc ,"Author Updated!"
ArcPy Mapping Module Jake K. Carr
Data Frame Objects
Now we know how to access map documents (.mxd).
Next we’ll talk about how to access items and elements inside ofthe map document.
The first type of item that we’ll want to access in a map documentis the map document data frame.
Map documents contain one or more data frames, but there isalways (only) one data frame that is active at any time.
ArcPy Mapping Module Jake K. Carr
Find the Active Data Frame
Open Train Stations.mxd to see what the active data frame is.
In Python, once we create a map document object we can find theactive data frame by accessing the activeDataFrame object:
import arcpy
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
actFrame = myMXD.activeDataFrame
print actFrame.name
Note that we have created an active data frame object byassigning the activeDataFrame output to actFrame.
ArcPy Mapping Module Jake K. Carr
Rename the Active Data Frame
We can access and assign various data frame properties by actingupon the data frame object we create.
Here, we re-name the data frame:
import arcpy
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
actFrame = myMXD.activeDataFrame
actFrame.name = "Arizona Rail Network"
print actFrame.name
ArcPy Mapping Module Jake K. Carr
Rename the Active Data Frame
What happened? Why didn’t the name change?
Not only did we not save the map document (with the save()method), but we also have to ‘Refresh the Table of Contents’.
That means we need to use the RefreshTOC() method:
import arcpy
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
actFrame = myMXD.activeDataFrame
actFrame.name = "Arizona Rail Network"
arcpy.RefreshTOC ()
myMXD.save()
ArcPy Mapping Module Jake K. Carr
How Do we Access all of the Data Frames?
Many map documents contain more than one data frame.
How do we access all of the data frames in a map document?
There’s a function for that ⇒ the ListDataFrames function.
Let’s create a list of data frames and then print out their namesand spatial references:
import arcpy
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
dfList = arcpy.mapping.ListDataFrames(myMXD)
for df in dfList:
print df.name
print df.spatialReference.name
ArcPy Mapping Module Jake K. Carr
How Do Make Another Data Frame the Active DataFrame?
We can make another data frame the active data frame with theactiveView property on our map document.
We can do so by assigning an alternate data frame from our dataframe list to the activeView property:
myMXD.activeView = dfList [1]
arcpy.RefreshActiveView ()
myMXD.save()
actFrame = myMXD.activeDataFrame
print actFrame.name
ArcPy Mapping Module Jake K. Carr
Layer Objects
Most of the time any particular data frame will contain more thanone layer.
We can access and manage the layers in a data frame by creatingLayer objects
Creating these Layer objects provides access to a whole bunch ofproperties and methods.
Perhaps the easiest way to create a layer object is by using theListLayers function1.
1http://resources.arcgis.com/en/help/main/10.1/index.html#//
00s30000002n000000
ArcPy Mapping Module Jake K. Carr
Listing Layers
Here, we create a list of layers in the first data frame, and assignthe first layer in that data frame to a Layer object called amtrak.
We can then pull valuable information from that layer, such as thedata source:
layerList = arcpy.mapping.ListLayers(myMXD , ’*’, dfList [0])
print layerList
amtrak = layerList [0]
print amtrak.isFeatureLayer
print amtrak.dataSource
What do you think the wildcard does here?
ArcPy Mapping Module Jake K. Carr
Manipulting Layers
We can ‘turn off’ a layer with the visible property:
amtrak.visible = False
arcpy.RefreshTOC ()
myMXD.save()
We can turn that layer back on:
amtrak.visible = True
arcpy.RefreshTOC ()
myMXD.save()
ArcPy Mapping Module Jake K. Carr
Manipulting Layers
We can ‘turn on’ a layer’s labels with the showLabels property:
amtrak.showLabels = True
arcpy.RefreshActiveView
myMXD.save()
Note the use of the RefreshActiveView function here. That isnecessary in order to to make the labels show up!2
Note that the RefreshActiveView function also refreshes the TOCas well!
2http://resources.arcgis.com/en/help/main/10.1/index.html#//
018v0000006s000000
ArcPy Mapping Module Jake K. Carr
Apply a Definition Query
A definition query controls which features of a particular layer areshown.
We can ‘write’ a definition query to a layer with thedefinitionQuery property.
fips = r"(’35039’,’35049’)"
defQuery = ’ "FIPS" IN ’ + fips
layerList [2]. definitionQuery = defQuery
arcpy.RefreshActiveView
myMXD.save()
Note the use of the IN statement in our query string: where havewe seen that before?
ArcPy Mapping Module Jake K. Carr
Layer Tools
We also have access to a number of ‘layer’ specific tools, such asthe Select Layer by Attribute tool.
The Select Layer by Attribute tool is just like the Select tool,except that the Select tool creates a new feature class/shapefilefrom the selected features.
The Select Layer by Attribute tool just creates a selection offeatures inside of the map document3.
Note that we will use our query skills here as well!
3http://resources.arcgis.com/en/help/main/10.1/index.html#//
001700000071000000
ArcPy Mapping Module Jake K. Carr
Select Layer by Attributes
Here we’ll set up a query string just like we did in createLine.py.
Our query will select two FIPS from the counties layer (how do weknow that?).
This code will create a new selection of these two counties.
fips = r"(’35039’,’35049’)"
strQuery = ’ "FIPS" IN ’ + fips
arcpy.management.SelectLayerByAttribute(layerList [2], "⇒⇒ NEW_SELECTION", strQuery)
arcpy.RefreshActiveView
myMXD.save()
ArcPy Mapping Module Jake K. Carr
Manipulate Extent by Selected Attributes
Just like the Zoom to Selected Features command in ArcMap, wecan now force the map extent to center/focus on the features weselected previously.
All it takes is the getSelectedExtent property.
This code will create a new selection of these two counties.
activeFrame = myMXD.activeDataFrame
activeFrame.extent = layerList [2]. getSelectedExtent
arcpy.RefreshActiveView
myMXD.save()
Of course we need to refresh and save!
ArcPy Mapping Module Jake K. Carr
How to Zoom Back
We can zoom back to the original extent using the getExtentproperty from one of the other, non-selected, layers.
Here we zoom back to the extent of the amtrak layer:
# Zoom Back
activeFrame.extent = amtrak.getExtent
arcpy.RefreshActiveView
myMXD.save()
ArcPy Mapping Module Jake K. Carr
To Remove The Selection
To remove a previous selection just use the Select Layer byAttribute tool again.
This time we’ll use the ”CLEAR SELECTION” option:
arcpy.management.SelectLayerByAttribute(layerList [2], "⇒⇒ CLEAR_SELECTION")
arcpy.RefreshActiveView
myMXD.save()
ArcPy Mapping Module Jake K. Carr
Applying Symbology
One of the most powerful automation techniques available with themapping module is the ability to apply the symbology of one layerto another.
We’ll need the UpdateLayer function4.
layerList = arcpy.mapping.ListLayers(myMXD , ’*’, dfList [1])
arcpy.mapping.UpdateLayer(dfList [1], layerList [0], amtrak)
arcpy.RefreshActiveView
myMXD.save()
What does the first line do here? What about the second line?
4http://resources.arcgis.com/en/help/main/10.1/index.html#//
00s30000003p000000
ArcPy Mapping Module Jake K. Carr
Applying Symbology from .Lyr File
What is a .Lyr File5?
A layer file is a template that holds a particular set of symbology.
Once you save a symbology to a layer file you can use that layerfile to set the symbology of an ∞ number of layers!
It’s easy to create a layer file, and it’s pretty easy to access a layerfile in ArcPy.
5http://resources.arcgis.com/en/help/main/10.1/index.html#//
00s500000013000000
ArcPy Mapping Module Jake K. Carr
Point and Click That!
ArcPy Mapping Module Jake K. Carr
Point and Click That!
ArcPy Mapping Module Jake K. Carr
Use That Layer File!
Now that we have a layer file we can apply that symbology to anynumber of map layers!
This is particularly useful when we have a script tool that producessome type of map output.
If we want to control the default behavior of how that outputdisplays on the map we can force the symbology from a layer fileto that output.
NOTE: It is common practice to include a layer file along with thescript when we create a script tool. Of course, it only does us anygood if we actually reference that layer file in the script!
ArcPy Mapping Module Jake K. Carr
Use That Layer File!
We’ll use the Layer function to ‘activate’ the layer file symbology.
import arcpy
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
dfList = arcpy.mapping.ListDataFrames(myMXD)
layerList = arcpy.mapping.ListLayers(myMXD , ’*’, dfList [1])
updateLayer = layerList [1]
sourceLayer = arcpy.mapping.Layer(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ GOOD.lyr")
arcpy.mapping.UpdateLayer(df , updateLayer , sourceLayer , True)
arcpy.RefreshActiveView
myMXD.save()
ArcPy Mapping Module Jake K. Carr
Controlling Output of Script Tools
When writing scripts for script tools we will often want to accessand modify the layers/features contained inside of the “Current”map document that the script tool will be ran in.
This is where we will most often use the syntax:
myMXD = arcpy.mapping.MapDocument("Current")
Note that by default, ArcMap will ‘put’ the output of geoprocessingoperation into the currently opened map document - which is nice.
However, sometimes we will want to control how that output getspresented (like by using a layer file probably).
ArcPy Mapping Module Jake K. Carr
Buffer Count Example
Suppose I am interested in creating a script tool that creates a setof buffer rings around a set of point features and then counts thenumber of point features that are located inside each of the bufferring features.
By default, ArcMap will add my buffer ring features to the mapdocument that I am working in.6
Also suppose that I want to force the symbology of that output tolook the same way every time - specifically the way I want it tolook!I’ll create a layer file containing my desired symbology and thenuse that layer file on my output buffer features.
6The assumption here is that I am working in a map document thatcontains those point features.
ArcPy Mapping Module Jake K. Carr
Buffer Count Example
Before we do that, let’s review the steps for creating a Pythonscript tool.
I First, write a ‘hard-coded’ script that performs all of ourgeoprocessing tasks
I Second, parameterize the ‘hard-coded’ script so that we canassociate it with a script tool
I Finally, we will manipulate the symbology of any output withthe UpdateLayer function.
The first thing is first - gotta get that hard code runnin’ right!
ArcPy Mapping Module Jake K. Carr
buffCnts HC.py
# Import ArcPy and set Workspace
import arcpy
arcpy.env.workspace = r"C:\ Lectures\Lecture 9\Maps"
arcpy.env.overwriteOutput = True
# Local Variables
in_features = "amtrak_stations.shp"
out_feature_class = "buff.shp"
buffer_distance_or_field = "50 Miles"
# Initial Buffer
arcpy.analysis.Buffer(in_features , out_feature_class , ⇒⇒ buffer_distance_or_field)
print "Buffers Created"
# Add Count Field
arcpy.management.AddField(out_feature_class , "Counts", "SHORT")
print "Field Added"
ArcPy Mapping Module Jake K. Carr
buffCnts HC.py
# ’Re ’-join Input Features and Buffers
# Order Matters!
arcpy.analysis.SpatialJoin(out_feature_class , in_features , "temp.⇒⇒ shp")
# Get Counts of Intersected Input Featurs
cnts = []
cursor = arcpy.da.SearchCursor("temp.shp", "Join_Count")
for row in cursor:
cnts.append(row [0])
del row
del cursor
print "Buffers Created:",len(cnts)
ArcPy Mapping Module Jake K. Carr
buffCnts HC.py
# Assign Counts to Buffer Features
n = 0
cursor = arcpy.da.UpdateCursor(out_feature_class , "Counts")
for row in cursor:
row [0] = cnts[n]
cursor.updateRow(row)
n += 1
del row
del cursor
print "Buffers Updated!"
# Clean Up
arcpy.management.Delete("temp.shp")
ArcPy Mapping Module Jake K. Carr
What Did We Do?
How do I make a layer file from this?
ArcPy Mapping Module Jake K. Carr
That’s Right!
ArcPy Mapping Module Jake K. Carr
Now What?
We’ve got a running hard-code.
We’ve got our preferred symbology.
What do we do now?7
7That’s right, we parameterize that hard-code.ArcPy Mapping Module Jake K. Carr
buffCnts Tool.py
# Import Modules & Overwrite Output
import os, sys , arcpy
arcpy.env.overwriteOutput = True
# Local Variables
in_features = arcpy.GetParameterAsText (0)
out_feature_class = arcpy.GetParameterAsText (1)
buffer_distance_or_field = arcpy.GetParameterAsText (2)
# Set Environment = Same Location as Input Features
arcpy.env.workspace = os.path.dirname(in_features)
# Initial Buffer
arcpy.analysis.Buffer(in_features , out_feature_class , ⇒⇒ buffer_distance_or_field)
arcpy.AddMessage("Buffers Created")
# Add Count Field
arcpy.management.AddField(out_feature_class , "Counts", "SHORT")
arcpy.AddMessage("Field Added")
ArcPy Mapping Module Jake K. Carr
buffCnts Tool.py
# ’Re ’-join Input Features and Buffers
# Order Matters!
arcpy.analysis.SpatialJoin(out_feature_class , in_features , "temp.⇒⇒ shp")
arcpy.AddMessage("Temp.shp Created")
# Get Counts of Intersected Input Featurs
cnts = []
cursor = arcpy.da.SearchCursor("temp.shp", "Join_Count")
for row in cursor:
cnts.append(row [0])
del row
del cursor
arcpy.AddMessage("Buffers Created :{0}".format(len(cnts)))
ArcPy Mapping Module Jake K. Carr
buffCnts Tool.py
# Assign Counts to Buffer Features
n = 0
cursor = arcpy.da.UpdateCursor(out_feature_class , "Counts")
for row in cursor:
row [0] = cnts[n]
cursor.updateRow(row)
n += 1
del row
del cursor
arcpy.AddMessage("Buffers Updated!")
# Clean Up Temporary
arcpy.management.Delete("temp.shp")
ArcPy Mapping Module Jake K. Carr
buffCnts Tool.py
# Symbology File - Located in the same folder as the script file
scriptpath = sys.path [0]
symbologyLayer = os.path.join(scriptpath ,"Buffers.lyr")
# Add buffers to the current map document and adjust symbology
# Add the frequency table to the current map document too
mxd = arcpy.mapping.MapDocument("CURRENT")
df = arcpy.mapping.ListDataFrames(mxd)[0]
newlayer = arcpy.mapping.Layer(out_feature_class)
arcpy.mapping.AddLayer(df, newlayer , "TOP")
layerSymb = arcpy.mapping.Layer(symbologyLayer)
updateLayer = arcpy.mapping.ListLayers(mxd , newlayer , df)[0]
arcpy.mapping.UpdateLayer(df , updateLayer , layerSymb , "TRUE")
arcpy.RefreshActiveView ()
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Make A Tool Out Of It
ArcPy Mapping Module Jake K. Carr
Success!
ArcPy Mapping Module Jake K. Carr
Another Useful Method
While we are in the process of writing and testing our script wemight prefer to not overwrite our original map document.
In this case we would prefer to save a copy of our map documentuntil we have our script running correctly; we’ll do this with thesaveACopy() method8.
import arcpy
myMXD = arcpy.mapping.MapDocument(r"C:\ Lectures\Lecture 9\Maps\⇒⇒ Train Stations.mxd")
# Do some stuff to Train Stations.mxd
# Don ’t want to overwrite Train Stations.mxd
myMXD.saveACopy(r"C:\ Lectures\Lecture 9\Maps\Train Stations2.mxd")
8http://resources.arcgis.com/en/help/main/10.1/index.html#//
00s30000000n000000
ArcPy Mapping Module Jake K. Carr