Creating a map book with inset maps

Map scripting can be integrated with Data Driven Pages to create a map book that includes custom inset maps on different pages while using a single map document. Custom logic can be introduced to control not only the visibility of the inset map but also its size, location, and extent.

Sample image of a map book with inset maps

Creating your map book

The first step is to create your map document and set up Data Driven Pages. You will want to design a baseline layout that all pages will share.

What are Data Driven Pages?

Adding the inset map to the layout

After you have your basic page layout, you need to insert a data frame that will serve as the inset map.

Steps:
  1. Click the Insert menu and choose Data Frame.
  2. Give the data frame a unique name. This name will be used to identify the data frame in the export script.
  3. Click OK to close the Data Frame Properties dialog box.
  4. Continue to create your inset map by adding the necessary layers and symbolizing them as desired.

Setting up the custom inset maps for individual pages

Because the extent, size, and position of the inset map will be set for individual pages during export, you need to know these values ahead of time so you can use them within your export script. This means that you first need to decide which pages should have an inset map. Then you need to navigate to each of those pages, set up the layout as you want it to appear in your final product, then record the appropriate settings that will be used in the final script.

The following steps walk through the process of manually recording the necessary inset map information for one page in the map series. These steps need to be repeated for each page containing an inset map.

Steps:
  1. Navigate to a page that will contain an inset map. Record the index value of the page by opening the Data Driven Pages toolbar and changing the display to Show Page.
    Data Driven Pages toolbar drop-down menu
  2. Position and size the inset map data frame on your page and set its extent.
  3. Record the Top, Left, Right, and Bottom values of the inset map's current extent. To find this information, open the inset map's Data Frame Properties dialog box, click the Data Frame tab, then change the extent to Fixed Extent so that the coordinate values appear.
    Fixed Extent option on Data Frame tab of the Data Frame Properties dialog box
  4. Record the information you need and change the extent back to Automatic. If the extent is set as something other than Automatic, you will not be able to change it in a script. The other extent types are fixed and you will get a runtime error.
  5. Click the Size and Position tab and record the x- and y- position values. Keep in mind that these reflect the current anchor point and need to be updated if the anchor point is ever changed.
  6. Record the values for the data frame's width and height as well.
  7. Close the Data Frame Properties dialog box, being careful not to apply any unwanted changes.

NoteNote:

You can record all this information manually, or you could run the following script inside the ArcMap Python window to write the information to a text file. You might have to adjust variable names, but the information will be written in such a way that you should be able to just copy and paste it into your script.

The following block of code can be run within the ArcMap Python window, and it will write the information about the current page layout to a specified text file.

import os 

# Create an output location variable
outputDirectory = r"C:\temp"  

# Open a text file to append info to
insetTxt = outputDirectory + r"\insetInfo.txt"
FILE = open(insetTxt, "a")

try:
    mxd = arcpy.mapping.MapDocument("current")
    df = arcpy.mapping.ListDataFrames(mxd, "Inset*")[0]
    ddp = mxd.dataDrivenPages
    infoList = []
    infoList.append("\n")
    # The following is information you would like to record
    # The text is written so it can be pasted directly into your script
    # This example assumes that 'pgIndex' is the variable for the current page id
    # and that 'dataFrame' is the variable for the data frame containing the inset map
    infoList.append("if (pgIndex == " + str(ddp.currentPageID) + "):\n")
    infoList.append("\tdataFrame.elementPositionX = " + str(df.elementPositionX) + "\n") 
    infoList.append("\tdataFrame.elementPositionY = " + str(df.elementPositionY) + "\n")
    infoList.append("\tdataFrame.elementHeight = " + str(df.elementHeight) + "\n") 
    infoList.append("\tdataFrame.elementWidth = " + str(df.elementWidth) + "\n")
    infoList.append("\tinsetExtent_" + str(ddp.currentPageID) + " = arcpy.Extent(" +
                    str(df.extent.XMin) + ", " + str(df.extent.YMin) + ", " + 
                    str(df.extent.XMax) + ", " + str(df.extent.YMax) + ")" + "\n")           
    infoList.append("\tdataFrame.extent = insetExtent_" + str(ddp.currentPageID) + "\n")
     
    FILE.writelines(infoList)
except:
    print "Writing to file failed"

# Close the text file
FILE.close()
NoteNote:

There may be other elements and settings that you want to change on a page-by-page basis, such as scale text for the inset map. To do so, follow steps similar to those outlined for the inset map to add the elements to your map and record their information. Then add code to your script to add or remove these elements as necessary during export.

Adding an extent indicator

You can add an extent indicator to your main map to highlight the area shown in your inset map.

Steps:
  1. Open the Data Frame Properties dialog box of your main map and click the Extent Indicators tab.
  2. Add the Inset Map data frame.
    Data frame added to Show extent indicator for these data frames list
  3. Use the available options to set its appearance.

Preparing the map document for export

After you have created your extent indicator and recorded the necessary information for your script, set up the map document so you do not see the extent indicator or inset map on every page.

Steps:
  1. Move the data frame containing the inset map off the printable area of the page.
  2. Change the extent of the inset map to something much greater than the extent of your main data frame so that the extent indicator will not appear on pages you don't want it to.
    Sample page layout with an inset data frame located off the page and zoomed to a large extent
  3. Save your map document.

Writing an export script

The following is a sample script that exports a map book with inset maps on pages 1 and 3.

The following script exports a map book with inset maps on pages 1 and 3.

import arcpy, os
# Create an output directory variable
#
outDir = r"C:\Project\MapBook\final_output"  

# 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:\Project\MapBook\zipCodePopulation.mxd"
tempMap = arcpy.mapping.MapDocument(mxdPath)
tempDDP = tempMap.dataDrivenPages

# Create objects for the layout elements that will be moving, e.g., inset data frame, scale text
dataFrame = arcpy.mapping.ListDataFrames(tempMap, "Inset Map")[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:\Project\MapBook\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
  # If the current page index matches, it will execute code to set up that page
  # If not, the page remains as is
  # Note: If you created a text file containing this information, this is where
  # you would paste in that code
  
  # Code for setting up the inset map on the first page #
  if (pgIndex == 1):
    # Set position of inset map to place it on the page layout
    dataFrame.elementPositionX = 0.5
    dataFrame.elementPositionY = 0.6
    # Set the desired size of the inset map for this page
    dataFrame.elementHeight = 2.0
    dataFrame.elementWidth = 2.0
    # Set the desired extent for the inset map
    insetExtent_1 = arcpy.Extent(-88.306778229417176, 41.590293951894907, -87.609922645465474, 42.300975912784295)
    dataFrame.extent = insetExtent_1


  # Code for setting up the inset map on the third page #
  if (pgIndex == 3):
    # Set up inset map
    dataFrame.elementPositionX = 3.25
    dataFrame.elementPositionY = 7
    dataFrame.elementHeight = 2.45
    dataFrame.elementWidth = 3.0
    insetExtent_3 = arcpy.Extent(-83.889191535, 41.870516098, -82.875460656, 42.72572048)
    dataFrame.extent = insetExtent_3

  # 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 by moving the data frame and resetting its extent after exporting the page
  # This will reset the page to the basic layout before exporting the next page
  #
  
  dataFrame.elementPositionX = 10 # Move inset data frame off the page
  dataFrame.scale = 350000000 # Change scale so extent indicator no longer visible in main data frame
  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()

In conclusion, by following this workflow, you can create map books with inset maps or other special features only on certain pages using a single map document.

Related Topics

3/5/2014