Multiple Data Driven Frames Using Python

2302
8
08-04-2016 10:08 AM
Johnkelly4
New Contributor II

I've been trying to write a script that can do the following:

Example:
-Two frames on a layout, one on top and one on the bottom
-10 data driven pages
-It would display DDP's 1, 3, 5, 7, 9 top frame and DDP's 2, 4, 6, 8, 10 on the bottom frame, for a total of 5 sheets of paper.

Below is what I have come up with so far. The script runs them one at a time instead of together. Anyone know what I am missing?

import arcpy
import time

mxd = arcpy.mapping.MapDocument("CURRENT")

#Lists all dataframes within the mxd
df1 = arcpy.mapping.ListDataFrames(mxd,"Layers")[0]
df2 = arcpy.mapping.ListDataFrames(mxd,"Layer 02")[0]
lyr = arcpy.mapping.ListLayers(mxd, "", df2)[0]
rows = arcpy.SearchCursor(lyr,"CATEGORY = 'Even'",
                          fields="Shape; Id; CATEGORY; Name",
                          sort_fields="Id A")

for pageNum in range(1, mxd.dataDrivenPages.pageCount + 1,2):  
  mxd.dataDrivenPages.currentPageID = pageNum
  for row in rows:
    df2.extent = row.Shape.extent
    df2.scale = 2400
    arcpy.RefreshActiveView()
    time.sleep(2)
    print row.getValue("Name")
del mxd


0 Kudos
8 Replies
DarrenWiens2
MVP Honored Contributor

This seems to work using a modern cursor. This works for 'nice' data, but you may have to do some work if you're missing IDs or something.

>>> import time
... mxd = arcpy.mapping.MapDocument("CURRENT")
... df1 = arcpy.mapping.ListDataFrames(mxd,"Layers1")[0]
... df2 = arcpy.mapping.ListDataFrames(mxd,"Layers2")[0] 
... index = 'buff' # my DDP index layer
... features = {row[0]:row[1] for row in arcpy.da.SearchCursor(index,['ID','SHAPE@'])} # all index features
... for pageNum in range(1,mxd.dataDrivenPages.pageCount,2):
...    mxd.dataDrivenPages.currentPageID = pageNum
...    df1.extent = features[pageNum].extent
...    df2.extent = features[pageNum+1].extent
...    arcpy.RefreshActiveView
...    time.sleep(2)
Johnkelly4
New Contributor II

Thank you sir! Your version seemed to work (and was much cleaner). What exactly did you mean by 'nice' data and missing IDs? What kinds of problems do you see with this?

0 Kudos
DarrenWiens2
MVP Honored Contributor

It just doesn't actually read the available IDs. It assumes that every ID exists between 1 and the length of the list. If you happened to have IDs 1, 2, 3, 5 (missing 4), when the loop is on 3 it will look for value 4 (pageNum+1), but since it's not there, there will be an error. If all your IDs exist, there should be no problem.

Johnkelly4
New Contributor II

Ah ok, I think I will be fine in that case. Will I be able to call on different field information with this? For example: I have a field called scale that determines the scale for each extent (1:2,400, 1:3,600, etc). So could something like this work:

import time  
mxd = arcpy.mapping.MapDocument("CURRENT")  
df1 = arcpy.mapping.ListDataFrames(mxd,"Layers")[0]  
df2 = arcpy.mapping.ListDataFrames(mxd,"Layer02")[0]
fc = "D:\Practice\Arcpy\New_Shapefile.shp"
index = fc # my DDP index layer

features = {row[0]:row[1] for row in arcpy.da.SearchCursor
            (index,['ID','SHAPE@','Scale'])} # all index features  
for pageNum in range(1,mxd.dataDrivenPages.pageCount,2):  
    mxd.dataDrivenPages.currentPageID = pageNum  
    df1.extent = features[pageNum].extent
    df1.scale = Scale
    df2.extent = features[pageNum+1].extent
    df2.scale = Scale
    arcpy.RefreshActiveView
    print ['ID']
    arcpy.mapping.ExportToPDF(mxd, r"D:\Practice\Arcpy\Page_" + str(pageNum) + ".pdf")
    time.sleep(2)
del mxd
0 Kudos
DarrenWiens2
MVP Honored Contributor

You would need to add the scale value into the features dictionary. Before, the dictionary had the form: {ID1:SHAPE1, ID2:SHAPE2,...}. Below, I've changed it to be like: {ID1:[SHAPE1,SCALE1], ID2:[SHAPE2,SCALE2]...}. So, later on, you can reference by ID (features[pageNum]) and get either the shape ([0]), or scale ([1]).

import time    
mxd = arcpy.mapping.MapDocument("CURRENT")    
df1 = arcpy.mapping.ListDataFrames(mxd,"Layers")[0]    
df2 = arcpy.mapping.ListDataFrames(mxd,"Layer02")[0
fc = "D:\Practice\Arcpy\New_Shapefile.shp"  
index = fc # my DDP index layer  
  
features = {row[0]:[row[1],row[2]] for row in arcpy.da.SearchCursor  
            (index,['ID','SHAPE@','Scale'])} # all index features    
for pageNum in range(1,mxd.dataDrivenPages.pageCount,2):    
    mxd.dataDrivenPages.currentPageID = pageNum    
    df1.extent = features[pageNum][0].extent  
    df1.scale = features[pageNum][1]
    df2.extent = features[pageNum+1][0].extent  
    df2.scale = features[pageNum+1][1]
    arcpy.RefreshActiveView  
    print ['ID'
    arcpy.mapping.ExportToPDF(mxd, r"D:\Practice\Arcpy\Page_" + str(pageNum) + ".pdf"
    time.sleep(2
del mxd
Johnkelly4
New Contributor II

Thank you! It worked out great! Sorry I am new to arcpy. So just to make sure I understand what happened -

The dictionary part is this?: features = {row[0]:[row[1],row[2]]...       (row[0] is attached to 'ID' and row[1] to 'Scale'?)

This part specifies what goes in each row? (index,['ID','SHAPE@','Scale'])} # all index features

0 Kudos
DarrenWiens2
MVP Honored Contributor

Yes, this is the line that builds the dictionary. It uses some shorthand called a dictionary comprehension:

features = {row[0]:[row[1],row[2]] for row in arcpy.da.SearchCursor(index,['ID','SHAPE@','Scale'])}

This line is equivalent to:

features = {}
with arcpy.da.SearchCursor(index,['ID','SHAPE@','Scale']) as cursor:
    for row in rows:
        features[row[0]] = [row[1],row[2]] # I think this is right, but may get key error, I can't remember

And, yes, you're mostly right about which part specifies what in row. The first value ('ID') becomes the first item in row (row[0]), second value ('SHAPE@') goes into row[1], and third value ('Scale') goes into row[2]. If you listed more fields, they would go into row[3], row[4], etc.

Johnkelly4
New Contributor II

Got it! Thanks again for all your help!!

0 Kudos