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
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)
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?
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.
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
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
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
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.
Got it! Thanks again for all your help!!