Two data frames with different extents in one layout

2938
5
Jump to solution
05-23-2012 10:51 PM
K_Clark
New Contributor II
I'm working on a project where I'm trying to print out a series of maps that just follow a power line.  The project will probably end up with about 150 11 x 17 inch maps.  I've placed two data frames, one above the other (landscape) so I can save paper and space.  I've used the strip grid generator for the data driven page to follow and used even/odd pages to drive the data frames.  So far I've been doing what Donna Erskine suggested on this thread (which is talking about the same thing I'm trying to solve).

Jeff Barrette's code suggestions inspired me to attempt to loop the one data frame code into two data frames.  However, this attempt ended in abysmal failure.  Every iteration seemed to confirm my suspicions that I know nothing about arcpy.mapping and data frames.

Here's the code at the point where I gave up:


# Experimental 2 dataframe pdf export  import arcpy from arcpy import env  document = r'C:\Users\Desktop\MapDocuments\Grids Tabloid v1.mxd'  mxd = arcpy.mapping.MapDocument(document) dataframe = arcpy.mapping.ListDataFrames(mxd)  lyr = arcpy.mapping.ListLayers(mxd, "*Grid*")[0] result = arcpy.GetCount_management(lyr) print 'Number of features in ' + str(lyr) + str(result)   print '\nStarting to loop through grids...\n' i = 0 while i < result:     print 'Printing PDF 0' + str(i)     j = 0     for frame in dataframe:         if j == 0:             df = dataframe             print 'Data frame0: ' + str(df)         elif j == 1:             df2 = dataframe             print 'Data frame1: ' + str(df2)         else:             print 'Something\'s wrong'             break                  lyr = arcpy.mapping.ListLayers(mxd, "*Grid*")         print 'Grid layers: ' + str(lyr)         rows = arcpy.SearchCursor(lyr.dataSource)         k = 0         for row in rows:             if k == i and j == 0:                 print 'in df arena'                 newDFExtent = row.getValue("Shape").extent                 df.extent = newDFExtent                 print df.rotation,                 print str() + ' has value from df 1!'             elif k == i and j == 1:                 print 'in df2 arena'                 newDFExtent2 = row.getValue("Shape").extent                 df2.extent = newDFExtent2                 print df2.rotation                 print str() + ' has value from df 2!'             elif k <> i:                 print str() + ' is NO value...'             k += 1         j += 1      arcpy.mapping.ExportToPDF(mxd, r'C:\Users\Desktop\PDFs\TestPDF ' \                               + str(0) + str(i) + '.pdf')     print 'Printed PDF 0' + str(i) + '\n'          i += 1           del mxd


There's a lot of junk code in there so I could tell where the program was, and what it was or wasn't doing.

The psuedo code goes like this:

Find the number of grids in the strip map  Identify the data frames  Break out the layers that have 'grid' in their names  Loop through the grid in the data frame      and set the different extents and rotations for each data driven data frame  Export the page to a PDF  Go to the next page


The PDF output did not display different extents or rotations.  I think from some of the other discussions that 10.1 might provide tools for this.  I'll be done with this project by then.

Any suggestions?
0 Kudos
1 Solution

Accepted Solutions
JeffBarrette
Esri Regular Contributor
If I understand this correctly, you are building a map series where each page has 2 extents that represent different segments along a strip map.  For example, one extent is all the odd numbered strip map extents and the other extent represents the even extents.

I had done this for a customer a while back.  My strategy was to use two MXDs.  Below is the code I wrote.

I'm using the DDP extent for each page from the DDP1.mxd to drive the extents in the NoDDP.mxd.

import arcpy, os path = os.getcwd()  mxd1 = arcpy.mapping.MapDocument(path + r"\DDP1.mxd")  #DDP enabled MXD mxd1df1 = arcpy.mapping.ListDataFrames(mxd1, "Top")[0]    #Reference the DF that DDP is based on  mxd2 = arcpy.mapping.MapDocument(path + r"\NoDDP.mxd")  #DDP is not enabled  mxd2df1 = arcpy.mapping.ListDataFrames(mxd2, "Top")[0]      #Top panel mxd2df2 = arcpy.mapping.ListDataFrames(mxd2, "Bottom")[0]  #Bottom panel mxd2panelAtxt = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "PanelA")[0] mxd2panelBtxt = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "PanelB")[0] mxd2pages = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "pages")[0]  if os.path.exists(path + "\MapBook.pdf"):   os.remove(path + "\MapBook.pdf") pdfDoc = arcpy.mapping.PDFDocumentCreate(path + "\MapBook.pdf")  totalPageCount = mxd1.dataDrivenPages.pageCount   #get the total pages from DDP1.mxd (and use those extents on the NoDDP.mxd page = 1  while page <= totalPageCount:   mxd1.dataDrivenPages.currentPageID = page   #this will be all odd pages (get the extent info)   panelAExt = mxd1df1.extent   panelARot = mxd1df1.rotation   panelAtxt = mxd1.dataDrivenPages.pageRow.Name     page = page + 1                                            #iterate the page number   mxd1.dataDrivenPages.currentPageID = page  #this will be all even pages   panelBExt = mxd1df1.extent   panelBRot = mxd1df1.rotation   panelBtxt = mxd1.dataDrivenPages.pageRow.Name   page = page + 1   if page > totalPageCount + 2:     break   mxd2df1.extent = panelAExt     #Now update the NoDDP mxd based on extents preserved from DDP1.mxd   mxd2df1.scale = 2400   mxd2df1.rotation = panelARot   mxd2panelAtxt.text = panelAtxt   mxd2df2.extent = panelBExt      #Do it again for the second panel   mxd2df2.scale = 2400   mxd2df2.rotation = panelBRot   mxd2panelBtxt.text = panelBtxt   mxd2pages.text = "Page " + str(page/2) + " of " + str(totalPageCount/2)   arcpy.mapping.ExportToPDF(mxd2, path + r"\Sheet" + str(page-2) + ".pdf")   pdfDoc.appendPages(path + r"\Sheet" + str(page-2) + ".pdf")   os.remove(path + r"\Sheet" + str(page-2) + ".pdf")  pdfDoc.saveAndClose() del mxd1, mxd2, pdfDoc

View solution in original post

0 Kudos
5 Replies
JeffBarrette
Esri Regular Contributor
If I understand this correctly, you are building a map series where each page has 2 extents that represent different segments along a strip map.  For example, one extent is all the odd numbered strip map extents and the other extent represents the even extents.

I had done this for a customer a while back.  My strategy was to use two MXDs.  Below is the code I wrote.

I'm using the DDP extent for each page from the DDP1.mxd to drive the extents in the NoDDP.mxd.

import arcpy, os path = os.getcwd()  mxd1 = arcpy.mapping.MapDocument(path + r"\DDP1.mxd")  #DDP enabled MXD mxd1df1 = arcpy.mapping.ListDataFrames(mxd1, "Top")[0]    #Reference the DF that DDP is based on  mxd2 = arcpy.mapping.MapDocument(path + r"\NoDDP.mxd")  #DDP is not enabled  mxd2df1 = arcpy.mapping.ListDataFrames(mxd2, "Top")[0]      #Top panel mxd2df2 = arcpy.mapping.ListDataFrames(mxd2, "Bottom")[0]  #Bottom panel mxd2panelAtxt = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "PanelA")[0] mxd2panelBtxt = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "PanelB")[0] mxd2pages = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "pages")[0]  if os.path.exists(path + "\MapBook.pdf"):   os.remove(path + "\MapBook.pdf") pdfDoc = arcpy.mapping.PDFDocumentCreate(path + "\MapBook.pdf")  totalPageCount = mxd1.dataDrivenPages.pageCount   #get the total pages from DDP1.mxd (and use those extents on the NoDDP.mxd page = 1  while page <= totalPageCount:   mxd1.dataDrivenPages.currentPageID = page   #this will be all odd pages (get the extent info)   panelAExt = mxd1df1.extent   panelARot = mxd1df1.rotation   panelAtxt = mxd1.dataDrivenPages.pageRow.Name     page = page + 1                                            #iterate the page number   mxd1.dataDrivenPages.currentPageID = page  #this will be all even pages   panelBExt = mxd1df1.extent   panelBRot = mxd1df1.rotation   panelBtxt = mxd1.dataDrivenPages.pageRow.Name   page = page + 1   if page > totalPageCount + 2:     break   mxd2df1.extent = panelAExt     #Now update the NoDDP mxd based on extents preserved from DDP1.mxd   mxd2df1.scale = 2400   mxd2df1.rotation = panelARot   mxd2panelAtxt.text = panelAtxt   mxd2df2.extent = panelBExt      #Do it again for the second panel   mxd2df2.scale = 2400   mxd2df2.rotation = panelBRot   mxd2panelBtxt.text = panelBtxt   mxd2pages.text = "Page " + str(page/2) + " of " + str(totalPageCount/2)   arcpy.mapping.ExportToPDF(mxd2, path + r"\Sheet" + str(page-2) + ".pdf")   pdfDoc.appendPages(path + r"\Sheet" + str(page-2) + ".pdf")   os.remove(path + r"\Sheet" + str(page-2) + ".pdf")  pdfDoc.saveAndClose() del mxd1, mxd2, pdfDoc
0 Kudos
K_Clark
New Contributor II
Thanks so much for posting the code, Jeff!  Using the one DDP mxd to drive the other is a great idea.  And it worked.

In setting up these two mxds to test this out, I had to figure out the ELEMENTS and how they were referenced, which I hadn't done before.  I also had to add a 'Name' field in the strip-grid attribute table so the mxd1.dataDrivenPages.pageRow.Name could access it.

The only thing I couldn't do was tell the North Arrow on the bottom data frame to rotate correctly.  It wanted to follow the initial data frame ('Top').  The rotation control is not exposed in arcpy.mapping.  If anyone has an idea of how to do this, I'd appreciate it if you could share the solution.  If it's ArcObjects code, I'm not sure how to wrap it in Python.  Hopefully, it's much simpler than that.  You can tell in my code how I struggled to get this to work.

Here are the components of the two mxds that I set up:

----------------------------------------------------------------------

The components of the DDP1.mxd

  • scale set to 1:3000

  • Only one data frame named "Top"

  • polyline named "FromMineralToElbe"

  • strip map polygon named "FromMineralToElbe_grid" with 16 grids

  • one MAPSURROUND_ELEMENT named "North Arrow" found in properties dialog box under Tab Size and Position in the ElementName box

  • data driven pages set with constant scale


The components of the NoDDP.mxd

  • scale set to 1:3000

  • 2 data frames named "Top" and "Bottom"

  • polyline named "FromMineralToElbe" in Top and Bottom

  • strip map polygon named "FromMineralToElbe_grid" with 16 grids in Top and Bottom

  • 2 TEXT_ELEMENT text boxes named "TitleA" and "TitleB" in the ElementName box

  • 2 MAPSURROUND_ELEMENT elements named "North Arrow A" and "North Arrow B"

  • 2 MAPSURROUND_ELEMENT elements named "Alternating Scale Bar A" and "Alternating Scale Bar B"

  • 2 MAPSURROUND_ELEMENT elements named "Scale Text A" and "Scale Text B"

  • A TEXT_ELEMENT named "pages" that uses <dyn> text properties


----------------------------------------------------------------------

Here's the code that works with both odd or even number of strip map grids (except for the North Arrow):

import arcpy, os
path = os.getcwd()

mxd1 = arcpy.mapping.MapDocument(path + r"\DDP1.mxd")  #DDP enabled MXD
mxd1df1 = arcpy.mapping.ListDataFrames(mxd1, "Top")[0]    #Reference the DF that DDP is based on
totalPageCount = mxd1.dataDrivenPages.pageCount   #get the total pages from DDP1.mxd (and use those extents on the NoDDP.mxd)
extraPage = 0
if totalPageCount%2 == 1:
  extraPage = 1

# setting up the second mxd with variables for the layers and elements
# so they can take the values of the first mxd
mxd2 = arcpy.mapping.MapDocument(path + r"\NoDDP.mxd")  #DDP is not enabled 
mxd2df1 = arcpy.mapping.ListDataFrames(mxd2, "Top")[0]      #Top panel
mxd2df2 = arcpy.mapping.ListDataFrames(mxd2, "Bottom")[0]  #Bottom panel
mxd2panelAtxt = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "TitleA")[0]
mxd2panelBtxt = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "TitleB")[0]
mxd2pages = arcpy.mapping.ListLayoutElements(mxd2, "TEXT_ELEMENT", "pages")[0]

# try to expose the North arrows on each dataframe so they can be rotated later
mxd2arrowA = arcpy.mapping.ListLayoutElements(mxd2, "MAPSURROUND_ELEMENT", "North Arrow A")[0]
mxd2arrowB = arcpy.mapping.ListLayoutElements(mxd2, "MAPSURROUND_ELEMENT", "North Arrow B")[0]

if os.path.exists(path + "\MapBook.pdf"):
  os.remove(path + "\MapBook.pdf")
pdfDoc = arcpy.mapping.PDFDocumentCreate(path + "\MapBook.pdf")

page = 1

while page <= totalPageCount:

  mxd1.dataDrivenPages.currentPageID = page   #this will be all odd pages (get the extent info)
  mxd1df1.name = "Top"
  panelAExt = mxd1df1.extent
  panelARot = mxd1df1.rotation
  panelAtxt = mxd1.dataDrivenPages.pageRow.Name
  
  # try to capture the characteristics of the top North arrow
  # since the page is odd
  northArrowA = arcpy.mapping.ListLayoutElements(mxd1, "MAPSURROUND_ELEMENT", "North Arrow")[0]

  # if the last 'page' is odd, delete all the layers for that page
  if page == totalPageCount and totalPageCount%2 == 1:
    df = arcpy.mapping.ListDataFrames(mxd2, "Bottom")[0]
    for lyr in arcpy.mapping.ListLayers(mxd2, "", df):
      arcpy.mapping.RemoveLayer(df, lyr)
      
    # then move all the bottom data frame elements off the page
    for elem in arcpy.mapping.ListLayoutElements(mxd2):
      if any("B" in s for s in elem.name):
        if elem.name == 'Alternating Scale Bar A':
          x = 0  # empty variable
        else:
          elem.elementPositionX = 15

  if page < totalPageCount:
    page = page + 1                            #iterate the page number
    mxd1.dataDrivenPages.currentPageID = page  #this will be all even pages
    
    # rename the dataframe object to force the North Arrow to recognize it
    # since the rotation angle is not exposed for the North arrow "MAPSURROUND_ELEMENT"
    # somehow the arrow still has the parent - child relationship to the "Top" dataframe
    mxd1df_phantom_2 = mxd1df1
    mxd1df2 = mxd1df_phantom_2
    mxd1df2.name = "Bottom"
    
    panelBExt = mxd1df2.extent
    panelBRot = mxd1df2.rotation
    panelBtxt = mxd1.dataDrivenPages.pageRow.Name
    
    # try to capture the characteristics of the top North arrow
    # since the page is even
    northArrowB = arcpy.mapping.ListLayoutElements(mxd1, "MAPSURROUND_ELEMENT", "North Arrow")[0]

  page = page + 1
  if page > totalPageCount + 2:
    break
  
  mxd2df1.extent = panelAExt     #Now update the NoDDP mxd based on extents preserved from DDP1.mxd
  mxd2df1.scale = 3000
  mxd2df1.rotation = panelARot
  mxd2arrowA = northArrowA
  mxd2panelAtxt.text = panelAtxt + ' - Top Frame'
  
  mxd2df2.extent = panelBExt      #Do it again for the second panel
  mxd2df2.scale = 3000
  mxd2df2.rotation = panelBRot
  mxd2arrowB = northArrowB
  mxd2panelBtxt.text = panelBtxt + ' - Bottom Frame'
  mxd2pages.text = "Page " + str(page/2) + " of " + str(totalPageCount/2 + extraPage)
  arcpy.mapping.ExportToPDF(mxd2, path + r"\Sheet" + str(page-2) + ".pdf")
  pdfDoc.appendPages(path + r"\Sheet" + str(page-2) + ".pdf")
  os.remove(path + r"\Sheet" + str(page-2) + ".pdf")

pdfDoc.saveAndClose()
del mxd1, mxd2, pdfDoc



Here's a jpeg of the last page of the map:

[ATTACH=CONFIG]15235[/ATTACH]

I would like to solve the North Arrow problem.  When you have two extents with varying rotations, you have to know how to orient the map.
0 Kudos
JeffBarrette
Esri Regular Contributor
Hmmm.  So if you add two North arrows (one for each data frame), they don't rotate?  Make sure the appropriate data frame is active when you insert each North Arrow.  Each North Arrow must be associated with a data frame.

Jeff
0 Kudos
JeffBarrette
Esri Regular Contributor
I was able to get this to work.  Attached are some results from a sample I'd like to post to the Resource Center.

[ATTACH=CONFIG]15283[/ATTACH]

Jeff
0 Kudos
K_Clark
New Contributor II
. . .  Make sure the appropriate data frame is active when you insert each North Arrow.  Each North Arrow must be associated with a data frame.

Jeff


Perfect!  I activated the bottom data frame and re-inserted a North Arrow and it worked!

Here's the result:

[ATTACH=CONFIG]15296[/ATTACH]

I had tried to associate the arrow with code, but obviously, the arrow is connected to the data frame via a GUID or other hidden attribute.

Thanks, again.
0 Kudos