I am writing a script to create thousands of maps and I am trying to create a table that updates for every map. Basically an updating table of the information specific to each map. I have been trying to link a an excel table to the layout view but arc does not seem to have that functionality. So what I am doing instead is creating a manual table in the layout view. I have 27 values for each map that I have been storing in a dictionary (using searchcursors to extract the info and store into dictionary).

I cannot copy and paste my table into here but it essentially looks this:

Receptors               AEGbuffer    CONbuffer    ERGbuffer
buffer                   1            10           19
schools                  2            11           20 
childcares               3            12           21
hospitals                4            13           22
nursinghomes             5            14           23
critical                 6            15           24
sw                       7            16           25
streams                  8            17           26
respop                   9            18           27

for k,v in sorted(table.items()):
    for elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT"):
        if elm.text == "1":  
            if k == 'AEGbuffer': elm.text= v
        if elm.text == "2":
            if k == 'AEGschools': elm.text = v
        if elm.text == "3":
            if k == 'AEGchildcares': elm.text = v
        if elm.text == "4":
            if k == 'AEGhospitals': elm.text = v
        if elm.text == "5":
            if k == 'AEGnursinghomes': elm.text = v
        if elm.text == "6":
            if k == 'AEGcritical': elm.text = v
        if elm.text == "7":
            if k == 'AEGsw': elm.text = v
        if elm.text == "8":
            if k == 'AEGstreams': elm.text = v
        if elm.text == "9":
            if k == 'AEGrespop': elm.text = v

this is just for the first row, the rest of the code is the same process for the pasting of the dictionary values.

where I am stuck: I do not know how to properly reset the newly changed values to their original 1-27 values so the next map can be easily produced. is there a tool or trick to this?

what I have tried: after I export the map I reopen the text elements and reverse the process like..

for k,v in sorted(table.items()):
    for elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT"):
         if k == 'AEGbuffer':
             if elm.text == v: elm.text = "1"
             and so on......

but this approach hasn't worked great. a few of the values are wrong when there are the same values a few times on the table.

  • I don't see where you have set those values in your script. Can't you just set them to an empty string or something before entering the loop? – jbchurchill Dec 22 '15 at 18:54

Instead of setting the text contents of each element set their name to something like "Text1" or even better you could make the element names match up with the key names in your table like 'AEGbuffer'. If it were me I would also add a suffix to the fields so i can make sure I am operating only on the table elements. You might come back later and add text elements that you don't want to include in your table loop.

enter image description here

Then your giant loop could look like this

for table_elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "*_table"):
     if text_elm.name == k:
          text_elm.text = v

To reset you just

for table_elm in arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "*_table"):
    table_elm.text = ""

EDIT: Based on your comments I think your real problem is your data format.

{'hospitals':{'AEGBuffer': 'None','ConBuffer': '65,200', 'ERGBuffer': 'None'}, 'schools':{'AEGBuffer': '600','ConBuffer': '7,300', 'ERGBuffer': '550'},'respop':{}}

lets you do:

#your k is now going to be the row name, i.e. hospitals and v is going to be another dictionary
for k,v in sorted(table.items()): 
    #this relies on elements being named hospitalERGBuffer, schoolCONBuffer etc.
    for bufferType, bufferValue in v.items():
        fieldName = str(k + bufferType) # i.e. 'hospitalsERGBuffer'
        table_elm = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", fieldName + "*")[0] #there's only going to be one if you've done this right.
            table_elm.text = bufferValue
|improve this answer|||||
  • Ryan I might not have explained it well so just to be 100% clear. 1. used the insert text to manually type out and paste the numbers 1-27 in my manually drawn table 2. The receptor names don't change neither do the top columns. Only the texts 1-27. 3. With ur advice are you saying for each column ex: 1,2,3,4,5,6,7,8,9 or the AEGbuffer column I should select them all and group them together, repeat the same process with the other columns.. Group them together and name them. Then with the big for loop use the "*_table" to access all of them. – ziggy Dec 22 '15 at 19:30
  • 4. I think a big problem with resetting the labels was that sometimes a few of the values in the whole dictionary would be the same, so when I go to reset it, the first instance a value shows up will be changed to that label (not neccesarily its original or correct one). Not sure if what I just said makes perfect sense to be honest, I'm having a tough time explaining it – ziggy Dec 22 '15 at 19:34
  • A dictionary for one map {'AEGhospitals': 'None', 'ERGschools': 'None', 'ERGrespop': 'None', 'CONschools': '4', 'ERGinfra': '1', 'CONstreams': '7', 'ERGbuffer': '1,000', 'AEGchildcares': '6', 'CONbuffer': '12,672', 'AEGcritical': '13', 'CONrespop': '2,436', 'ERGchildcares': 'None', 'AEGnursinghomes': 'None', 'CONnh': 'None', 'CONsw': 'None', 'ERGhospitals': 'None', 'AEGsw': 'None', 'AEGrespop': '11,366', 'AEGstreams': '42', 'ERGstreams': 'None', 'AEGschools': '8', 'CONchildcares': '1', 'CONinfra': '5', 'ERGnh': 'None', 'ERGsw': 'None', 'CONhospitals': 'None', 'AEGbuffer': '12,672'} – ziggy Dec 22 '15 at 19:36
  • Cramming all the data into a single dictionary makes it harder to loop through this intelligently. This format might be easier to work with: {'hospitals':{'AEGBuffer': 'None','ConBuffer': '65,200', 'ERGBuffer': 'None'}, 'schools':{'AEGBuffer': '600','ConBuffer': '7,300', 'ERGBuffer': '550'},'respop':{}} etc. – Ryan Dec 22 '15 at 20:00
  • With my original advice I'm not saying to group the fields, just name them individually so they match up with the keys in your data format. – Ryan Dec 22 '15 at 20:29

i have figured out a neat trick when trying to reset text elements. If you put your mxd path inside the loop you are going through you do not need to write code to reset your text elements

first way that you must manually reset:

mxd = "path"
for lay in fc:
   ##extract info for map
    for x in text_elements:
        if x == "word": x = "number"
    for x in for x in text_elements:
        if x == "number": x = "word"

but you do not need to reset the text elements if you put the mxd path inside your main loop!

for lay in fc:
    mxd = "path"
   ##extract info for map
    for x in text_elements:
        if x == "word": x = "number"
|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.