1

I'm a newcomer to Python and have been working on using ArcPy scripts to automate Data Driven Pages in ArcGIS. I would like some help please to use ArcObjects in ArcPy and change map grids in DDP with different scale maps. I have copied two blocks of code below. The first block of code works (originally copied from Stack Exchange, please excuse my clumsy additions) and produces a single pdf of four maps. Because the first map is an Overview I would like to swap grids, with one for the Overview and another for the remaining three maps. The second block is my attempt at integrating Alex Tereshenkov's code for accessing ArcObjects in ArcPy (https://tereshenkov.wordpress.com/2017/04/16/access-to-arcmap-map-document-grid/), and so far I have managed to produce a 4 page map, but it is the same map on each page, with no change in map grid. Clearly I'm out of my depth! Is it even possible to make this work? And if anyone can explain the logic behind Alex's clever "for g in grids" 6 lines of code, that would be great too. Apologies for all the code...

Code 1:

import arcpy, os
import sys

# Create an output directory variable
#
outDir = r'C:\AA\Project\SCRATCH'

# Create a new, empty pdf document in the specified output directory
# This will be your final product
finalpdf_filename = outDir + r"\FinalMapBook.pdf"
if os.path.exists(finalpdf_filename): # Check to see if file already exists, delete if it does
 os.remove(finalpdf_filename)
finalPdf = arcpy.mapping.PDFDocumentCreate(finalpdf_filename)

# Create a Data Driven Pages object from the mxd you wish to export

mxdPath = r'C:\AA\Project\SCRATCH\01M_Project_20190117.mxd'
tempMap = arcpy.mapping.MapDocument(mxdPath)
tempDDP = tempMap.dataDrivenPages

# Create objects for the layout elements and layers

sScaleBar = arcpy.mapping.ListLayoutElements(tempMap, "MAPSURROUND_ELEMENT", "1in3thou")[0]
lScaleBar = arcpy.mapping.ListLayoutElements(tempMap, "MAPSURROUND_ELEMENT", "1in20thou")[0]
tplayer = arcpy.mapping.ListLayers(tempMap, "testpits")[0]
balayer = arcpy.mapping.ListLayers(tempMap, "bsa_opf")[0]
bblayer = arcpy.mapping.ListLayers(tempMap, "bsa_ev")[0]
bmalayer = arcpy.mapping.ListLayers(tempMap, "bsa_opf_mat")[0]
bmblayer = arcpy.mapping.ListLayers(tempMap, "bsa_ev_mat")[0]

# Instead of exporting all pages at once, you will need to use a loop to export one at a time
# This allows you to check each index and execute code to add inset maps to the correct pages

for pgIndex in range(1, tempDDP.pageCount + 1, 1):

 # Create a name for the pdf file you will create for each page
 temp_filename = r'C:\AA\Project\SCRATCH\temp_pdfs\MB_' + \
                        str(pgIndex) + ".pdf"
 if os.path.exists(temp_filename):
   os.remove(temp_filename)

# The following if statements check the current page index against given  values

# overview page

pageNumList = [1]
if pgIndex in pageNumList:
  sScaleBar.elementPositionX = -10
  sScaleBar.elementPositionY = 3.8
  lScaleBar.elementPositionX = 2.8
  lScaleBar.elementPositionY = 3.8
  tplayer.visible = False
  balayer.visible = True
  bblayer.visible = True
  bmalayer.visible = False
  bmblayer.visible = False

# borrow material assessment pages

pageNumList = [2,3,4]
if pgIndex in pageNumList:
 sScaleBar.elementPositionX = 2.8
 sScaleBar.elementPositionY = 3.8
 lScaleBar.elementPositionX = 2.8
 lScaleBar.elementPositionY = -0.8
 tplayer.showLabels = True
 tplayer.visible = True
 balayer.visible = False
 bblayer.visible = False
 bmalayer.visible = True
 bmblayer.visible = True

# Code to export current page and add it to mapbook
tempDDP.exportToPDF(temp_filename, "RANGE", pgIndex)
finalPdf.appendPages(temp_filename)

# Clean up your page layout

sScaleBar.elementPositionX = -10
lScaleBar.elementPositionX = 45
arcpy.RefreshActiveView()

# Clean up

del tempMap

# Update the properties of the final pdf

finalPdf.updateDocProperties(pdf_open_view="USE_THUMBS",
                         pdf_layout="SINGLE_PAGE")

# Save your result

finalPdf.saveAndClose()

Code 2:

import sys
from comtypes.client import GetModule, CreateObject
import arcpy, os
import arcpy.mapping as mp
from snippets import GetStandaloneModules, InitStandalone
esriCarto = GetModule(r"C:\Program Files (x86)\ArcGIS\Desktop10.6  \com\esriCarto.olb")

# Running this code for the first time, you would need to import
# the ?StandaloneModules?. Can comment out later.
GetStandaloneModules()
InitStandalone()

# Create an output directory variable

outDir = r'C:\AA\Project\SCRATCH'

# Create a new, empty pdf document in the specified output directory
# This will be your final product

finalpdf_filename = outDir + r"\FinalMapBook.pdf"
if os.path.exists(finalpdf_filename):
  os.remove(finalpdf_filename)
finalPdf = arcpy.mapping.PDFDocumentCreate(finalpdf_filename)

# Create a Data Driven Pages object from the mxd you wish to export

mxdPath = r'C:\AA\Project\SCRATCH\01M_Project_20190117.mxd'
tempMap = mp.MapDocument(mxdPath)
tempDDP = tempMap.dataDrivenPages

for pgIndex in range(1, tempDDP.pageCount + 1, 1):

  # Create a name for the pdf file you will create for each page

    temp_filename = r'C:\AA\Project\SCRATCH\temp_pdfs\MB_' + \
                        str(pgIndex) + ".pdf"
    if os.path.exists(temp_filename):
        os.remove(temp_filename)

#......................

def export_map(show_scale):
handle_grids(show_scale)

tempMap = mp.MapDocument(mxdPath)
tempDDP = tempMap.dataDrivenPages
df = mp.ListDataFrames(tempMap,"Layers")[0]
sScaleBar = mp.ListLayoutElements(tempMap, "MAPSURROUND_ELEMENT", "1in3thou")[0]
lScaleBar = mp.ListLayoutElements(tempMap, "MAPSURROUND_ELEMENT", "1in20thou")[0]
tplayer = mp.ListLayers(tempMap, "testpits")[0]
balayer = mp.ListLayers(tempMap, "bsa_opf")[0]
bblayer = mp.ListLayers(tempMap, "bsa_ev")[0]
bmalayer = mp.ListLayers(tempMap, "bsa_opf_mat")[0]
bmblayer = mp.ListLayers(tempMap, "bsa_ev_mat")[0]

# overview page
if show_scale == 'large':
     pageNumList = [1]
     if pgIndex in pageNumList:
        sScaleBar.elementPositionX = 2.8
        sScaleBar.elementPositionY = -1.2
        lScaleBar.elementPositionX = 2.8
        lScaleBar.elementPositionY = 2.8
        tplayer.visible = False
        balayer.visible = True
        bblayer.visible = True
        bmalayer.visible = False
        bmblayer.visible = False


# Code to export current page and add it to mapbook

tempDDP.exportToPDF(temp_filename.format(show_scale), "RANGE", pgIndex)
finalPdf.appendPages(temp_filename)

# remaining pages

if show_scale == 'small':
 pageNumList = [2,3,4]
 if pgIndex in pageNumList:
    sScaleBar.elementPositionX = 2.8
    sScaleBar.elementPositionY = 2.8
    lScaleBar.elementPositionX = 2.8
    lScaleBar.elementPositionY = -0.8
    tplayer.showLabels = True
    tplayer.visible = True
    balayer.visible = False
    bblayer.visible = False
    bmalayer.visible = True
    bmblayer.visible = True

 # Code to export current page and add it to mapbook

tempDDP.exportToPDF(temp_filename.format(show_scale), "RANGE", pgIndex)
finalPdf.appendPages(temp_filename)

 # create grid objects

def handle_grids(show_scale):
#creating a map document object
mxdObject = CreateObject(esriCarto.MapDocument, interface=esriCarto.IMapDocument)
mxdObject.Open(mxdPath)

#accessing the map
IMap = mxdObject.ActiveView.FocusMap

activeView = mxdObject.ActiveView
pageLayout = activeView.QueryInterface(esriCarto.IPageLayout)
graphicsContainer = pageLayout.QueryInterface(esriCarto.IGraphicsContainer)

#IFrameElement
frameElement = graphicsContainer.FindFrame(IMap)

#IMapFrame
mapFrame = frameElement.QueryInterface(esriCarto.IMapFrame)

#IMapGrids
mapGrids = mapFrame.QueryInterface(esriCarto.IMapGrids)
[mapGrids.MapGrid(i) for i in xrange(mapGrids.MapGridCount)]

grids = [mapGrids.MapGrid(i) for i in xrange(mapGrids.MapGridCount)]

for g in grids:
    print g.Name
    if show_scale.lower() in g.Name.lower():
        g.Visible = True
    else:
        g.Visible = False

for g in grids:
    print g.Name, g.Visible

#......................

export_map('large')
export_map('small')

arcpy.RefreshActiveView()

# Clean up

del tempMap

# Update the properties of the final pdf

finalPdf.updateDocProperties(pdf_open_view="USE_THUMBS",
                         pdf_layout="SINGLE_PAGE")

# Save your result

finalPdf.saveAndClose()
0

I've never done this using DDP. I'm not entirely sure what the point of using DDP in python would be when you could just as easily use a search cursor (or another method) on your index layer to change the map extent or even a second feature class that has a common attribute to the features in your index. DDP is more limiting than the cartographic functions in ArcPy. However, specifically regarding line 62 in the code you referenced. He is simply creating a list of the number of Grids he has defined in his map:

#
mapGrids = mapFrame.QueryInterface(esriCarto.IMapGrids)
[mapGrids.MapGrid(i) for i in xrange(mapGrids.MapGridCount)]

grids = [mapGrids.MapGrid(i) for i in xrange(mapGrids.MapGridCount)]

for g in grids:
    print g.Name
#

So grids is a list of as many Grids he has in the MXD from which he can reference the grid Name.

  • @ RGfromRWBJV. Thanks for replying. Sorry but I don't understand your answer. I'm using DDP to create a series of maps with different scales, and I want to be able to toggle between larger and smaller grids/graticules to match the map scales by accessing ArcObjects through ArcPy. Changing map scale itself is not the issue, the problem is the grid/graticule does not change dynamically with the map scale. – Chars Feb 18 at 5:54
  • Correct. The code you referenced is doing the same thing without DDP. Namely starting on line 30 he is stating that at large format scales, zoom to the state of California via a selection query. So rather than using DDP, you can use a search cursor: desktop.arcgis.com/en/arcmap/10.3/analyze/arcpy-data-access/… to loop through all the features in your index layer. Using the search query you can pan, zoom, etc. to the index feature or also to a feature that is referenced in the attribute table of your index. – RGfromRWBJV Feb 19 at 19:30
  • For example, say you have a feature class of projects that you are using as an index and you want to make a local scale map of the project area and an overview where the project is located at the county scale. If you have the county attributed in your project feature class and a separate county layer, you can use the search cursor (in the past I also created a dictionary, ie. key is the project name and the value is the county) to zoom to the associated county export a large format map and then zoom to the project and export a local. – RGfromRWBJV Feb 19 at 19:43
  • Specifically regarding the map grids portion statement you copied in your post. He is first calling the ArcObject statement for map grids within the map, then listing all map grids within the map as grids ie. in a map with two map grids, grids = [mapGrid[0], mapGrid[1]]. Then he creates a for loop of the list and prints the name of the list, as identified in the data frame properties (for example, "Graticule" and "Measured Grid".... However since your map extent is not changing, the issue is with the DDP portion not the map grids. – RGfromRWBJV Feb 19 at 20:51
  • Here are the v10.1-10.3 ArcObject documentation, the new are on the arcgis.com site somewhere: resources.arcgis.com/en/help/arcobjects-java/api/arcobjects/… – RGfromRWBJV Feb 19 at 20:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.