Dynamic Layout Title (ArcGIS Pro)

3678
11
Jump to solution
12-18-2017 01:04 PM
Business_IntelligenceSoftware
Occasional Contributor

Is there a way to make the title of a layout dynamic with a feature class? I know there is dynamic text with the Map Frame, Project Name, Metadata, and many other things. From the research I have done it seems like it might have been possible in ArcMap, but I have been unable to find anything in ArcGIS Pro that would allow for the layout title to be dynamic with a feature class. 

To expand a little further. I have a large arcpy script where 80 layouts are created (from 1 template layout) and exported into a PDF, but right now each layout has the same generic title so sometime it is hard to know what data is being shown in the layout. This problem could be solved if the layout's title was Dynamic with the feature class that is being portrayed in the layout.

I considered using the following code, which uses the TextElement, but it looks to me like I would have to specify each individual title for every layout. And if I have 80+ layouts, that could take a long time. 

p = arcpy.mp.ArcGISProject("Current")
for lyt in p.listLayouts():    
    for elm in lyt.listElements("TEXT_ELEMENT"):        
        if elm.name == "title": # this is the element name set via text properties                 
            # add layout feature class check logic            
            elm.text = "New Title" # changing title name

Am I reading this right?

Is there a better way?

1 Solution

Accepted Solutions
Business_IntelligenceSoftware
Occasional Contributor

The final code I used to get the results I was looking for is:

import arcpy
from arcpy import env
import sys
import os
import datetime
elm_name = "My Dynamic Title" # the name you assign to the title (TEXT) element
p = arcpy.mp.ArcGISProject(r"C:\arcGIS_Shared\Python\CenterHeatMaps.aprx")
for lyt in p.listLayouts("Layout_King"): # get the element
    for elm in lyt.listElements("TEXT_ELEMENT"):
        if elm.name == elm_name:
            text_elm = elm
            break

for m in p.listMaps(): # loop through your layer / layouts / maps
    for lyr in m.listLayers("BCBS*"):
        new_title=lyr.name # do your logic with the layer
        elm.text=new_title
        lyt.exportToPDF(r"C:\arcGIS_Shared\Exports" + "\\BCBS_" + elm.name[13:] + ".pdf") # export the map
        print(elm.name[13:])

Thank you everyone for your help and input!

View solution in original post

11 Replies
XanderBakker
Esri Esteemed Contributor

Have you considered using a TextElement—ArcPy | ArcGIS Desktop  and updating the text property?

Business_IntelligenceSoftware
Occasional Contributor

I updated my question in response to your TextElement suggestion

0 Kudos
XanderBakker
Esri Esteemed Contributor

You could read out the layer used fro a layout, determine the name in the layout and use that as the text in the text element. Do you have all the 80 layouts in a single ArcGIS Pro project? How are the map frames defined for each layout?

0 Kudos
Business_IntelligenceSoftware
Occasional Contributor

I forgot to specify that it is really just one layout that is being used as a template. So the 80 PDFs are really just different versions of the same layout

0 Kudos
XanderBakker
Esri Esteemed Contributor

So what do you change in the process to create the 80 maps? 

0 Kudos
Business_IntelligenceSoftware
Occasional Contributor

I'll just list the steps that the script goes through.

1) Geocode Addresses

2) Summarize Within Loop based on locations (80 locations) - so 80 feature classes

3) Apply Symbology to 80 feature classes

4) Export PDFs after referencing Bookmarks (80 bookmarks based on the previous locations)

So each layout is based on a different Bookmark and depicts the corresponding feature class also

0 Kudos
XanderBakker
Esri Esteemed Contributor

For each map you generate, I suppose you have access to the layer it is based on. The name property will provide you the name which could be used for the title. In Pro you will have to add a text element and give it a name:

This name can be used to "find" the element and change the title. Something along the lines of this (untested) code:

elm_name = "My Dynamic Title" # the name you assign to the title (TEXT) element
aprx = arcpy.mp.ArcGISProject("Current")

# get the element
for lyt in aprx.listLayouts():
    for elm in lyt.listElements("TEXT_ELEMENT"):
        if elm.name == elm_name: 
            text_elm = elm
            break

# loop through your layer / layouts / maps
for m in aprx.listMaps():
    for lyr in m.listLayers():
        # do your logic with the layer
        new_title = lyr.name
        elm.text = new_title
        # export the map
‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
Business_IntelligenceSoftware
Occasional Contributor

Xander, thanks for all your help with my question. I realize that the code you are suggesting is untested, so I have been experimenting with it the best I can. Here is my updated version of your code:

 

import arcpy
from arcpy import env
import sys
import os
import datetime
elm_name = "My Dynamic Title"
p = arcpy.mp.ArcGISProject(r"C:\arcGIS_Shared\Python\CenterHeatMaps.aprx")
for lyt in p.listLayouts("Layout_King") [0]:
   for elm in lyt.listElements("TEXT_ELEMENT"):
      if elm.name==elm_name:
         text_elm=elm
         break

for m in p.listMaps():
   for lyr in m.listLayers("BCBS*"):
      new_title=lyr.name
      elm.text=new_title
      lyt.exportToPDF(r"C:\arcGIS_Shared\Exports" + "\\BCBS" + elm.name[13:] + ".pdf")
      print(elm.name[13:])

But when I try and run it it gives me the following error:

Traceback (most recent call last):
   File "<string>", line 8, in <module>
TypeError: 'Layout' object is not iterable

Do you know what I'm doing wrong? Also, does it look like I'm at least on the right track?

0 Kudos
DanPatterson_Retired
MVP Emeritus

When you sliced the list of layouts to get the  first element, it is no longer a list, hence it isn't iterable.  Xander's example didn't do the slicing as you will notice, so his code gets a list of layouts, not a single layout.  If there were only one layout, it would be contained in a list.  So, you could try dumping the slice ( aka [0] ) if you are sure there is only one layout with that name.

for lyt in p.listLayouts("Layout_King")[0]: