Python Data Driven Pages does not loop through list

1136
10
Jump to solution
01-16-2013 08:24 AM
SusanWhitney
New Contributor III
I am new to python (and the forum) and am trying to export data driven pages with a definition query. I have a list (right now only two items) for the ddp to loop through. The final pdf files have the correct name and cover sheet, but the map data is the same in both files and is not one of the items in the list. It looks like I have a problem with my definition query, but have hit a wall on what could be the problem.

# Import ArcPy import arcpy  # Set up variables # Location of pole map .mxd document mxdDoc = r"G:\GEOSPATIAL\Publishing\Pole\Pole_QtrSec.mxd"  # Create the MapDocument object mxd = arcpy.mapping.MapDocument(mxdDoc) layers = arcpy.mapping.ListLayers (mxd, "SURVEY_GRID_BNDRY")  # Overwrite an existing file arcpy.env.overwriteOutput = True  # Output directory for the pole maps outDir = r"G:\GEOSPATIAL\Publishing\Pole"  # Set the workspace arcpy.env.workspace = outDir  twpList = ['\"TOWNSHIP_C\" = \'D5\' AND \"RANGE_CD\" = \'7\'',\            '\"TOWNSHIP_C\" = \'D6\' AND \"RANGE_CD\" = \'7\'']  for twpName in twpList:     layers[0].definitionQuery = twpName     print layers[0].definitionQuery          # The final mapbook name taken from the list     finalPDFfn = outDir + "\\" + twpName [16:18] + twpName [38:39] + "Pole.pdf"          # Create the final PDF -- which is just an empty shell right now     finalPDF = arcpy.mapping.PDFDocumentCreate(finalPDFfn)      # A temporary pdf file for processing     tmpPDF = outDir + "\\PoleMapPages.pdf"      # Let the user know what is happening!     print "Exporting " + twpName [16:18] + twpName [38:39]          # Export the data driven pages in the mxd to a temporary PDF     print "Exporting map pages to the temporary PDF"     ddp = mxd.dataDrivenPages.exportToPDF(tmpPDF)      # Append the temporary pdf to the final pdf     # Cover, map pages, back cover     print "Appending Map Pages"     finalPDF.appendPages (r"G:\GEOSPATIAL\Publishing\Pole\PoleCovers\Covers_" + twpName [16:18] + twpName [38:39] + ".pdf")     finalPDF.appendPages(tmpPDF)     finalPDF.appendPages(r"G:\GEOSPATIAL\Publishing\TwpGrid_Color8x11.pdf")      # Set properties for Adobe Reader and save PDF.     finalPDF.updateDocProperties(pdf_open_view = "USE_THUMBS", pdf_layout = "SINGLE_PAGE")     finalPDF.saveAndClose()  # Clean up print "Cleaning up" # Delete the temporary PDF using the ArcPy function if arcpy.Exists(tmpPDF):                  arcpy.Delete_management(tmpPDF)   # Delete objects del mxd, tmpPDF, ddp    
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor
I was fiddling with this more - only the def query part, and George you are right.  Although you could technically create a layer object from scratch and so forth, then proceed to updatelayer using the created object, there's no need in this case (my fault to complicate matters).

I tested this and it works fine -- very bare-bones stuff (also caught a spelling error, it's 'saveACopy' not as in my last post)
See this, modified slightly to work with my sample data:
import os, arcpy arcpy.env.overwriteOutput = True  mxdDoc = r"F:\qryDefTest\qryTestDoc.mxd" mxd = arcpy.mapping.MapDocument(mxdDoc)  # assuming the 1st data frame df = arcpy.mapping.ListDataFrames(mxd)[0]  # queries - SDE workspace twpList = ['AK in (' + str(1240290) + ', ' + str(1240311) + ')',\            'AK in (' + str(1240281) + ', ' + str(1240338) + ')']  # layer (the 1st and only layer in the map) layer = arcpy.mapping.ListLayers(mxd, '', df)[0]  i = 1 for twpName in twpList:     layer.definitionQuery = twpName     mxd.saveACopy(os.path.splitext(mxdDoc)[0] + str(i) + os.path.splitext(mxdDoc)[1])     i += 1  del mxd


What tipped me off on this 'shortcut' is the code sample at the bottom of the page on ListTableViews - similar concept:
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00s300000006000000

Sorry I don't have more -- this should only resolve the layer querying part (and correct my misdirection on the use of updatelayer in this case, thank you George).  So if you have other errors, you still have to troubleshoot the other components of your code.

Enjoy,
Wayne

View solution in original post

0 Kudos
10 Replies
T__WayneWhitley
Frequent Contributor
UpdateLayer
Resource Center » Professional Library » Geoprocessing » The ArcPy site package » Mapping module » Functions » Managing Documents and Layers
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00s30000003p000000

I think that is what you are missing, see the sample code there...if I may use the analogy, it seems similar to changing values for a row object in an update cursor - it doesn't take effect until you update...

Hope that helps.
-Wayne
0 Kudos
SusanWhitney
New Contributor III
Thank you, Wayne for the information. I am not sure about this, since I don't have a source layer to update to.
0 Kudos
T__WayneWhitley
Frequent Contributor
Your queries look fine to me, although I would use a combination of AddFieldDelimiters and in-line variable substitution to keep them a little more manageable.  AddFieldDelimiters is nice in case you want to apply your script to different workspaces where the query 'punctuation' on the fieldnames is sensitive, without having to change your script.

Back to what I still think is your issue, I don't think it is enough to simply define the query def property - I think you have to use 'updatelayer' to commit the change to layer properties in the map.  Look at the Layer object webhelp doc...you can do something like 'get' the map's current layer properties with your layer object created in your script, then 'replace' or update the map's current layer with the one you modified in the script - make sense now?  Conceptually, it is like dragging and dropping layers between maps (an easy way to copy layers from one map to another) -- if you change the layer props in one map, the changes are not reflected in the other.  But you can 'drag and drop' to the other map again to sort of refresh the layer, reflecting the current modifications.

Most importantly (in this conceptual example), you will have 2 copies of the layer in the map you 'recopied' to, the 'old' one refecting the original properties and the 'new' one you updated or changed the properties on.  You have to remove or delete the old feature layer from the map...so instead of adding-new-removing-old with your script, the analogous operation in your script is to use 'updatelayer'.  That's why you need to 'read' the position of the layer in the map and 'stamp' it with your modified layer object.

Hope that makes sense - you don't have to use layer files or a source layer from another map.

Enjoy,
Wayne
0 Kudos
T__WayneWhitley
Frequent Contributor
Actually, you may be onto something - but let's simplify and test with this:
import os, arcpy
arcpy.env.overwriteOutput = True

outDir = r"G:\GEOSPATIAL\Publishing\Pole"
arcpy.env.workspace = outDir

mxdDoc = r"G:\GEOSPATIAL\Publishing\Pole\Pole_QtrSec.mxd"
mxd = arcpy.mapping.MapDocument(mxdDoc)

# assuming the 1st data frame
df = arcpy.mapping.ListDataFrames(mxd)[0]

# queries - should make these sensitive to the workspace type?
twpList = ['\"TOWNSHIP_C\" = \'D5\' AND \"RANGE_CD\" = \'7\'',\
           '\"TOWNSHIP_C\" = \'D6\' AND \"RANGE_CD\" = \'7\'']

# Your layer
layer = arcpy.mapping.ListLayers (mxd, "SURVEY_GRID_BNDRY", df)[0]

i = 1
for twpName in twpList:
    layer.definitionQuery = twpName

    # oops, should be 'saveACopy' not as I originally posted, 'savACopy'
    mxd.saveACopy(os.path.splitext(mxdDoc)[0] + str(i) + os.path.splitext(mxdDoc)[1])
    i += 1


I did not test this, but if it works I think it is the 'shortcut' you were trying to use.  UpdateLayer I will have to experiment later -- must be greater utility when you need to use one layer object (in layer files or from separate maps, etc.) in transferring properties to another.

Almost forgot to explain the output of this code:
- it uses your output directory
- for the 2 queries, it produces 2 map docs for you to check to see if it works (whether the query is applied, please check the layer properties of your subject map layer)

If this successfully runs, please check the following 2 map docs:
G:\GEOSPATIAL\Publishing\Pole\Pole_QtrSec1.mxd
G:\GEOSPATIAL\Publishing\Pole\Pole_QtrSec2.mxd

Enjoy,
Wayne
0 Kudos
GeorgeNewbury
Occasional Contributor
You might try:

twpList = [""" "TOWNSHIP_C" = 'D5' AND "RANGE_CD" = '7' """,\
           """ "TOWNSHIP_C" = 'D6' AND "RANGE_CD" = '7' """]


I've started to use the triple quotes lately, as the single,doubles and escape characters can get confusing. Of course if you try this then you'll need to modify all of the string references, e.g.
twpName [16:18]
. It would also simplify everything if you took the township and range text out of the list. e.g.


twpList = [['D5','7'],['D6','7']]
for twp in twpList:
    twpdefQuery = """ "TOWNSHIP_C" = '""" + twp[0] + """' AND "RANGE_CD" = '""" + twp[1] + "'"  
    layers[0].definitionQuery = twpdefQuery

##And from then on instead of using twpName [16:18] you could use twp[0] or twp[1]


I was just working with setting definition queries. I didn't call updatelayer at all, but I did move the layer to a group layer, which may have called some sort of update under the table.

George
0 Kudos
T__WayneWhitley
Frequent Contributor
I was fiddling with this more - only the def query part, and George you are right.  Although you could technically create a layer object from scratch and so forth, then proceed to updatelayer using the created object, there's no need in this case (my fault to complicate matters).

I tested this and it works fine -- very bare-bones stuff (also caught a spelling error, it's 'saveACopy' not as in my last post)
See this, modified slightly to work with my sample data:
import os, arcpy arcpy.env.overwriteOutput = True  mxdDoc = r"F:\qryDefTest\qryTestDoc.mxd" mxd = arcpy.mapping.MapDocument(mxdDoc)  # assuming the 1st data frame df = arcpy.mapping.ListDataFrames(mxd)[0]  # queries - SDE workspace twpList = ['AK in (' + str(1240290) + ', ' + str(1240311) + ')',\            'AK in (' + str(1240281) + ', ' + str(1240338) + ')']  # layer (the 1st and only layer in the map) layer = arcpy.mapping.ListLayers(mxd, '', df)[0]  i = 1 for twpName in twpList:     layer.definitionQuery = twpName     mxd.saveACopy(os.path.splitext(mxdDoc)[0] + str(i) + os.path.splitext(mxdDoc)[1])     i += 1  del mxd


What tipped me off on this 'shortcut' is the code sample at the bottom of the page on ListTableViews - similar concept:
http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00s300000006000000

Sorry I don't have more -- this should only resolve the layer querying part (and correct my misdirection on the use of updatelayer in this case, thank you George).  So if you have other errors, you still have to troubleshoot the other components of your code.

Enjoy,
Wayne
0 Kudos
SusanWhitney
New Contributor III
Thank you, I'll start working with your suggestions. Meeting this afternoon, so I'll hopefully let you know by tomorrow how this works.
0 Kudos
T__WayneWhitley
Frequent Contributor
A tip:

refresh() is required after changing the layer def query in order to 'redefine' the DDP index limits.

That is, insert the command as in the following---
layer.definitionQuery = twpName
mxd.dataDrivenPages.refresh()


I discovered that quite by accident.  That's all I have - I can't say whether this is an error affecting the rest of your code but I am assuming you are attempting to define the DDP index based on you def query?  If so, definitely a factor.

-Wayne
0 Kudos
SusanWhitney
New Contributor III
The code ran with the modifications. Adding the refresh makes sense.
Thank you all for your assistance. On to the next portion of the code .... selection!
Have a good day.
0 Kudos