This section highlights guidelines for working with the arcpy.mp module. It also provides insight on the design of the arcpy.mp API and suggests strategies for different scenarios.
It must work with existing projects
The arcpy.mp module cannot create projects. It was designed primarily to modify objects within existing projects (.aprx) or layer files (.lyr or .lyrx) for the purpose of map or data automation. As the API continues to expand in ArcGIS Pro, more constructor functions are being introduced. For example, the ArcGISProject class has the createMap and createLayout methods and a number of other constructor methods. Not everything can be created in a project, so you may still need to author a project ahead of time with the elements you intend to manipulate using arcpy.mp.
The following are a few examples of how arcpy.mp can be used:
- Replace a layer's data source.
- Iterate through a series of extents, find and replace text values, and export the page layout to PDF.
- Build a complete map book by appending PDF documents into a final product.
Note:
It is possible to make changes to existing projects or layer files and save the changes to a new file using the saveACopy method on the ArcGISProject or Layer objects.
Reference a project on disk or use the CURRENT keyword
There are two ways that a project can be referenced using the ArcGISProject function. The first, and recommended, method is to provide a system path to the location of the project (.aprx) on disk. This technique is most versatile because a script can be run outside of the application. Referencing a specific project on disk provides more control in terms of how the script will run because a given script may not work on all projects.
An example of providing a full path to a project.
import arcpy
aprx = arcpy.mp.ArcGISProject(r"C:\Projects\YosemiteNP\Yosemite.aprx")
The second technique is to use the CURRENT keyword as an input parameter to the ArcGISProject function. This technique only works from within the application because the ArcGISProject object references the project that is currently loaded into the application. Using CURRENT is helpful when quickly testing and learning the scripting capabilities and command syntax within the Python window. You may start off learning the syntax in the Python window and start pasting those lines of code into a more permanent, larger script saved to disk. Script tools that use the CURRENT keyword must also be run from within the application.
An example of using the CURRENT keyword.
aprx = arcpy.mp.ArcGISProject('current')
Add layers and work with template projects
As mentioned in the section above, arcpy.mp does not allow you to completely author new projects. However, you can author template projects with all the appropriate elements, page sizes, orientations, and so on, ahead of time, and use arcpy.mp to manipulate the contents.
A common scenario is to author a template project with no layers and use the addLayer, addLayerToGroup, or insertLayer methods on the Map object to add layers to a map in the project.
Another common scenario involves map books with facing pages. The left and right pages include different offsets to make space for the binding. This scenario includes having two layouts in a single project: one layout for left pages and another for right pages. The arcpy.mp scripting logic is used to pull together all the individual pages into a final output multipage PDF.
Author all objects with a unique name
To easily reference an element in a layout so it can be accessed and modified, the item must have a unique name. Many of the arcpy.mp list functions—for example, listLayouts, listMaps, listBookmarks, listTables, listLayers, listLabelClasses, and listElements—have a wildcard parameter that allows you to filter on the name property. These list functions always return a Python list object. To reference an element from the Python list, you can either iterate through the list using a loop or you can append an index number at the end of the function. If you use the wildcard parameter and specify a unique name, the resulting Python list will always have one item, and it can be referenced using an index value of 0.
The code below shows an example of referencing a text element on a layout using its name property.
aprx = arcpy.mp.ArcGISProject('CURRENT')
lyt = aprx.listLayouts('Main Attractions')[0]
title = lyt.listElements('TEXT_ELEMENT', 'title')[0]
Ideally, all layers and tables within a single project would be given a unique name, but that is not always possible. If there are cases in which you need to have duplicate layer and table names in a map but need to be able to isolate one item from another, you will need to author the item so it can be distinguished using other properties, for example, the description property.
The code below shows an example of how layers with the same name, Roads, in the same map, Yosemite National Park, can be further isolated using the maxThreshold property of the Layer object. These layers have the same data source but are drawn differently depending on the scale at which they are being viewed.
import arcpy
aprx = arcpy.mp.ArcGISProject(r"C:\Projects\YosemiteNP\Yosemite.aprx")
mp = aprx.listMaps('Yosemite National Park')[0]
for lyr in mp.listLayers():
if lyr.name == 'Roads':
if lyr.maxThreshold == 10000:
lyr.visible = True
if lyr.maxThreshold == 100000:
lyr.visible = False
aprx.save()
del aprx
The better alternative for the sample above would be to name each layer differently, for example, Roads - large scale and Roads - small scale.
Manage the visibility of elements on a layout
There may be a situation in which you are creating a map series and there are some pages that need additional map elements that not all pages need, for example, an extra inset map, additional picture, or text elements, and so on. Rather than authoring separate layouts just for those scenarios, you can author a single layout with all the possible layout elements and use arcpy.mp scripting logic to control the visibility of the element. There are two methods that can be used. First, set the element's visible property to True or False depending on the individual page and element configuration. Second, physically move the element off the page if it is not needed. You can do this by modifying either the elementPositionX or elementPositionY properties. If the element is not on the layout and it gets printed or exported, the element will not display.
In the example below, the resulting layout will display a different style scale bar based on the scale of the current data frame. If the scale is larger than 1:25,000, the scale bar units will be in meters. If the scale is smaller than or equal to 1:25,000, the scale bar units will be in kilometers.
import arcpy
aprx = arcpy.mp.ArcGISProject(r"C:\Projects\YosemiteNP\Yosemite.aprx")
lyt = aprx.listLayouts("Main Attractions")[0]
m_scale = lyt.listElements("MAPSURROUND_ELEMENT", "m scale bar")[0]
km_scale = lyt.listElements("MAPSURROUND_ELEMENT", "km scale bar")[0]
mf = lyt.listElements("MAPFRAME_ELEMENT", "Yose*")[0]
if mf.camera.scale < 25000:
m_scale.elementPositionX = 5 #Or m_scale.visible = True (on the page)
km_scale.elementPostitionX = 15 #Or km_scale.visible = False (off the page)
else:
m_scale.elementPositionX = 15 #Or m_scale.visible = False (off the page)
km_scale.elementPostitionX = 5 #Or km_scale.visible = True (on the page)
aprx.save()
del aprx
One method may be easier than another depending on the situation. For example, if you prefer to use visible to control the display of an element, the trade-off may be that it is more difficult to manage multiple items on a layout that overlay one another.