I have created a script tool for ArcMap 10.3.1 that will move a legend around a data frame so as not to obscure a specified map layer when using data driven pages. However, I'm encountering an interesting problem when attempting to align the legend to the right edge of the data frame.
Here is the code I use to align the legend (the legend is anchored at the bottom left):
inset.elementPositionX = (DataFrame.elementPositionX + DataFrame.elementWidth) - inset.elementWidth
Now, this script works perfectly until I have the "Only show classes that are visible in the current map extent" box checked in the legend's properties. Having this checked causes the legend to resize as the program iterates through each page (depending on what is visible on the map), and when it does so it either leaves a gap or overruns the data frame edge.
The interesting thing is that while the "Only show classes that are visible in the current map extent" is checked on in the legend's properties, if I iterate through each page manually, running this little align snippet in the python window after changing pages, it works perfectly.
So, my question is: why does this not work while it's running in a script tool, but does when running manually? It's almost as if ArcMap isn't able to keep up with itself (if that even makes sense...)
Note* this tool was built to run on an open MXD, not outside of one.
To test try this:
Open an MXD, add two layers - one an index layer for DDP, and a second layer that is symbolized by categories. Make sure that not all categories show up in every DDP. Then, insert a legend, go to it's properties, check the "Only show classes that are visible in the current map extent" box. Then as you click through your DDPs, your legend should (unless all element descriptions are the same width) change shape.
Next, add this to the python window:
mxd = arcpy.mapping.MapDocument("Current") SecondaryObject = "Legend" inset = arcpy.mapping.ListLayoutElements(mxd, "", SecondaryObject) PrimeObject = "Main View" DataFrame = arcpy.mapping.ListDataFrames(mxd, PrimeObject) inset.elementPositionX = (DataFrame.elementPositionX + DataFrame.elementWidth) - inset.elementWidth
Next, iterate through your DDP to observe the snippet in action, working.
In the full version of the DDP with movable legend script, the align takes place after the DDP is switched to each new page. First the legend is moved back to it's starting position, and if the "intersect" function returns > 0 from there, it moves on to a new position:
for pageNum in range(1, mxd.dataDrivenPages.pageCount + 1): #setup naming and path for output maps path = mxd.filePath bn = os.path.basename(path)[:-4] mxd.dataDrivenPages.currentPageID = pageNum insetDefaultX = inset.elementPositionX insetDefaultY = inset.elementPositionY #check defualt position for intersect intersect = checkIntersect(inset) if intersect == 0: #if it doesn't intersect, print the map arcpy.mapping.ExportToEPS(mxd, exportFolder + "\\" + bn + "_"+ str(pageNum) + ".eps", "Page_Layout",640,480,300,"BETTER","RGB",3,"ADAPTIVE","RASTERIZE_BITMAP",True,False) else: #intersect != 0: #move inset to SE corner inset.elementPositionX = (DataFrame.elementPositionX + DataFrame.elementWidth) - inset.elementWidth inset.elementPositionY = DataFrame.elementPositionY