Set DDP index layer with python?

2766
14
Jump to solution
12-04-2012 12:31 PM
TomKearns
Occasional Contributor II
I have a set of Data Driven Pages with counties and land cover already made.  I am trying to create a tool that will take input of a county name and spawn a new set of DDP at a 4000M per grid square.  I have been able to select, clip and  create a smaller grid focusing on the area of interest but can not reset the index layer.  Is this possible, and if not is there a work around?
Tags (2)
0 Kudos
14 Replies
T__WayneWhitley
Frequent Contributor
Here's an idea, and I'm keeping this very simple if for no other reason I haven't seen the rest of your code to know exactly how you are implementing this - maybe it doesn't matter though.  Let me suggest this:

1- Suppose you had all grids you needed for your project in a single feature class....i.e. all county grids in a single source layer.
2- The layer object has a parameter that accepts an expression for a definition query, so if you had your grid sets attributed with a county name, you could use the name in a def query, and pass it to the layer object.
3- Use UpdateLayer to replace the index layer object with the def query layer object.
4- Refresh the map...

I think what has happened is somehow the layer references have been mixed up - the wildcard param on ListLayers is based on the Name property of the layer...so with all the layer manipulations I suppose it is possible to have passed in the wrong layer name for the data source.  Also, remember ListLayers can certainly return more than one layer- don't think this is your problem, but just have to be a little careful with this, maybe query the description if you have one to check which layer you actually have an object on.

You can loop to fetch county names from a list (or I think you said this parameter would be furnished one county at a time?) and form the def query from the fetched county name - I think you should be able to get the index layer object from the map and pass in the def query, then simply execute the UpdateLayer function to 'copy' it to the index layer in the map.  Not sure, but you may not even need to execute UpdateLayer if you're setting a property on a direct reference to a layer object in the map.

Of course, this all depends on if the DDP will 'play nice' with this technique.

So then (check my syntax, this is untested):

#make sure only 1 layer in the map is called 'index'- or include logic to verify.
lyr = arcpy.mapping.ListLayers(mxd, 'index', df)[0]

#test this string for proper syntax-- pass in your county param here.
lyr.definitionQuery = 'your def query string here'
arcpy.RefreshActiveView()

See the definitionQuery property (a read/write property) here:

Layer (arcpy.mapping)
Desktop » Geoprocessing » ArcPy » Mapping module
http://resources.arcgis.com/en/help/main/10.1/index.html#//00s300000008000000


EDIT:
Ah, here I think (see link below) confirms that you don't need UpdateLayer - see the example at the bottom of this page (although this is in used in conjuction with ListTableViews, i.e. tables in the map instead of feature layers, ListLayers should work the same way.)  ...meaning that the returned objects and setting of those object properties should be directly reflected in the map.  The 'refresh' wasn't necessary because there are no features to view - it's a table only.  Notice the def query string.

http://resources.arcgis.com/en/help/main/10.1/index.html#//00s300000006000000

table = arcpy.mapping.ListTableViews(mxd, "TrafficAccidents", df)[0]
table.definitionQuery = "[Accidents] > 5"
mxd.save()
0 Kudos
T__WayneWhitley
Frequent Contributor
This may not be conclusive testing to suit all your end purposes, but I wanted to report back here that I ran a simple test today on the index layer of one of my existing DDP mxds and I was able to set the definitionQuery property and successfully refresh the DDP so that other operations such as exporting, printing, etc., recognized the 'new' index (no adding, removing, or updating the index layer was necessary).  I imagine you've got enough other layer updates to do than to worry about where your index layer reference went (remember an earlier post I suggested creating a 'master' fc containing all county grids so that you can filter them by county from the layer object perspective using a def query).

Here's an abbreviated example:

import arcpy
arcpy.env.workspace = r'< your workspace string (mine was a gdb) >'
testdoc = r'< your mxd path >'
 
mxd = arcpy.mapping.MapDocument(testdoc)
df = arcpy.mapping.ListDataFrames(mxd, '< your dataframe where your DDP index resides >')[0]

# set layer object reference to the index page
lyr = arcpy.mapping.ListLayers(mxd, '< your index layer name >', df)[0]

# create the appropriate field delimiters for the query string based on the workspace type
indexPageField = arcpy.AddFieldDelimiters(arcpy.env.workspace, '< your index layer page fieldname >')

# create the query, in this case, filtering for pages less than 6 (pgs 1-5)
qry = indexPageField + ' < 6'

# set the layer objects definition query
lyr.definitionQuery = qry

# finally, refresh the DDP -- this is the critical step which will crash if the query is unacceptable...
mxd.dataDrivenPages.refresh()

# here you can test the DDP by getting the pageCount, printing, exporting, etc...
pgCnt = mxd.dataDrivenPages.pageCount
print pgCnt   # based on the query, results in 5 pages

# success!
# try changing the definition query to see if the DDP changes correspondingly
qry = indexPageField + ' < 11'
lyr.definitionQuery = qry
mxd.dataDrivenPages.refresh()
 
pgCnt = mxd.dataDrivenPages.pageCount
print pgCnt  # based on the changed query, results in 10 pages
by Anonymous User
Not applicable

I know I'm several years behind here, but I'm a little confused on the query above. The query is assuming the grids are in the same gdb, etc., and that way you just pull in the appropriate file within the gdb? 

 

My problem is similar- I am trying to update the index layer dynamically in Python. I want to switch out my "dummy" index layer with the layer that gets fed to the mxd dynamically. Would I use a similar approach as above?

0 Kudos
JeffBarrette
Esri Regular Contributor
I did something similar.  I built an electrical distribution application that allowed someone to enter in a Feeder ID, it would then query the 100's of 1000's of features that match that ID, then use GridIndexFeature to dynamically build a DDP index grid for those features only, and then export the extents/pages out to a multi-page PDF.

Similar to your scenario, I could not do it all with one MXD.  For some reason if I dynamically switch out the DDP index layer data source in the map I run the script against, weird, unexplainable things happened.  So I did it with 2 mxds.  The first MXD had basic layers that I queried and used to build the dynamic DDP index layer.  The second MXD is already DDP enabled and when I call .refresh it works well.

The partial code below shows how I used the two MXDs:

import arcpy, os, sys
relpath = os.path.dirname(sys.argv[0])
arcpy.env.overwriteOutput = True

####Stript tool parameters
feederID = arcpy.GetParameterAsText(0)

##Part 1 - Create subset to build features
mxd = arcpy.mapping.MapDocument(relpath + r"\\FeederMap1.mxd")

##Reference appropriate layers and set definition queries
POCLyr = arcpy.mapping.ListLayers(mxd, "Primary Overhead Conductor")[0]
POCLyr.definitionQuery = "\"FEEDERID\" = '" + feederID + "'" 

# Execute GridIndexFeatures
arcpy.GridIndexFeatures_cartography(relpath + r"/Scratch.gdb/DDPgrid", [POCLyr], "INTERSECTFEATURE", "", "", "10000 feet", "6500 feet")
del mxd, POCLyr, PUCLyr, stationLyr

##Part 2 - Prepare Feeder Map and Export to PDF

mxd2 = arcpy.mapping.MapDocument(relpath + r"\\FeederMap2.mxd")
#Reference appropriate layers and set definition queries
for lyr in arcpy.mapping.ListLayers(mxd2):
  if lyr.name == "Primary Overhead Conductor":
    lyr.definitionQuery = "\"FEEDERID\" = '" + feederID + "'"
    POCLyr = lyr
  
ddp = mxd2.dataDrivenPages
ddp.refresh()

ddp.exportToPDF(relpath + r"\Feeder_" + feederID + ".pdf")
del mxd2


I hope this helps,
Jeff
T__WayneWhitley
Frequent Contributor
Interesting workaround, I knew it would work.  Thanks for your post, I will likely need this in the future.
I figured 'replacing' completely the index datasource was 'breaking' the DDP functionality and wondered if I should have tested the part where you'd need to restructure the page numbering (or other fields) since those values may need to be dynamically maintained.  I haven't confirmed, but I suspect as long as you aren't deleting the index fc or layer, you could go as far as clearing it of features and loading it with new ones.....sort of similar to 'reloading' an SDE fc to circumvent having to re-establish privileges, etc. - maybe that's a weak analogy....

Regardless, I see what you mean, thank you very much for the alternate working solution!

-Wayne
0 Kudos