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.
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.
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.
- Click the Insert menu and choose Data Frame.
- Give the data frame a unique name. This name will be used to identify the data frame in the export script.
- Click OK to close the Data Frame Properties dialog box.
- 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.
- 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.
- Position and size the inset map data frame on your page and set its extent.
- 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.
- 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.
- 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.
- Record the values for the data frame's width and height as well.
- Close the Data Frame Properties dialog box, being careful not to apply any unwanted changes.
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*") 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()
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.
- Open the Data Frame Properties dialog box of your main map and click the Extent Indicators tab.
- Add the Inset Map data frame.
- 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.
- Move the data frame containing the inset map off the printable area of the page.
- 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.
- 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") # 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.