ListLayoutElements for loop issue

2335
5
11-30-2010 08:09 AM
RyanKelley
New Contributor II
When running my script via ArcToolbox, it takes 1-2 minutes when using the ListLayoutElements for loop. Both when using "TEXT_ELEMENT" and the "MAPSURROUND_ELEMENT". Other for loops are fine (ListLayers).  Replacing the text or moving the scale bar is not the problem, it is just the single lines of code:

for elm in arcpy.mapping.ListLayoutElements(MXD, "TEXT_ELEMENT"):
& 
for elmScaleBar in arcpy.mapping.ListLayoutElements(MXD, "MAPSURROUND_ELEMENT"):


Why is this happening? When I run it in the arcpy window, it is lightening quick. I've built a brand new MXD too.

Thanks, ryan
0 Kudos
5 Replies
JeffBarrette
Esri Regular Contributor
Thanks Ryan,

This is something we are currently looking into.  We also have observed the performance issues concerning ListLayoutElements as well.

You will see a difference between running this as a stand-alone script vs. running in the Python Window using CURRENT because the implementations are different.  Here is a very brief explanation: with CURRENT the code is acting directly on the map document in the application and all objects are directly accessible.  As a stand alone script, the code is acting against a map document that does not exist in an application but rather in a "fictitious" window that needs to be activated each time objects called.

We hope to have this addressed for SP2.

Thanks,
Jeff
0 Kudos
RyanKelley
New Contributor II
Thanks for the response Jeff.  It is interesting that in some MXDs this is not a problem, and others it is.  I thought my MXD was corrupt, so I started a new, very simple MXD. However, when I started adding a graticule, other text and legend elements, etc. I noticed that loop starting to get really slow.

Anyway, SP2 sounds good... and I'll stop trying to trouble shoot this.

Ryan
0 Kudos
AprilBrough
New Contributor II
I am encountering this issue with a python script (running from WING) with 10.0 SP3.  It must not have been resolved in SP2?  If I run the command in ArcMap, I find 264 layout elements (I am not quite sure how I have that many).  At any rate, I assume from Jeff's description that there are memory issues with creating that many instances of a virtual/fictional window?  Not sure how to work around this... any suggestions?  I am trying to query out elements whose names contain a partial string, and move them on the page, so I need the list that ListLayoutElements returns.
0 Kudos
JeffBarrette
Esri Regular Contributor
I'm fairly certain we addressed the memory issues discovered prior to SP2.  That does NOT mean you didn't find something else.

It sounds like you are surprised that there are so many elements in your MXD.  Have you tried saving it out to a new file?  Have you tried determining what the extra objects are and deleting them?

Here is a trick that I use to minimize the number of times I call ListLayoutElements because every time you call it, it must iterate through all of your elements:

for elm in arcpy.mapping.ListLayoutElements(mxd):
  if elm.name == "title": title = elm
  if elm.name == "north arrow": northArrow = elm
  if elm.name == "graphic": graphic = elm


The above code calls ListLayoutElements once vs 3 separate times like below:

title = arcpy.mapping.ListLayoutElements(mxd, "TEXT_ELEMENT", "title")[0]
northArrow = arcpy.mapping.ListLayoutElements(mxd, "MAPSURROUND_ELEMENT", "north arrow")[0]
graphic = arcpy.mapping.ListLayoutElements(mxd, "GRAPHIC_ELEMENT", "graphic")[0]


I hope this helps,
Jeff
0 Kudos
AprilBrough
New Contributor II
Thanks for the quick response, Jeff. 

Someone else prepared the mxd I am working with, which contains two legends and 12 scales bars that had been turned into graphics for detailed customization.  I realized that that there were many, many subgroups of the elements within the overall group elements I was trying to control.  This was done to assist with the manual relative alignment of the individual elements.  I ungrouped everything in the mxd, then recreated only the major element groups.  I also reworked the scale bar customization so I could use multiple dynamic bars instead of the graphic bars provided.

This reduced my total list of elements from 264 to 87, which increased the speed of my script.  Unfortunately, the script is still incredibly slow.  With the mxd I am currently running my script against (when I had 264 elements), ListLayoutElements ran for a couple hours and then my machine's resources were insufficient (I don't remember the exact message, but I believe it was caused by memory problems).  In the past, when running my script against a different mxd, this portion of the script was almost instantaneous.  The previous mxd had two legends and 12 scale bars as well, all of which contained grouped graphic elements.  I am not sure what the difference is between the mxds.

Thanks for the tip about just creating the list of elements once, then subsequently filtering the desired elements.  That will greatly increase the speed of my script. Unfortunately, the ListLayoutElements is in multiple functions that I call for a series of projects (sometimes I run 200+ projects at once), so I will still be suffering quite a delay in total script runtime.  I could pass the list as an argument, but only within each project iteration, as each project generates its own mxd.  I will probably end up passing it between functions within a project, given how much time it would save.  It just seems more tedious that being able to create a quick list as needed within a function.

I will keep playing with this, and see if I determine any other differences between the mxds.  With ListLayoutElements as my only method of reaching a graphic legend or scale bar, I am not sure what my other options are for decreasing execution time.

Thanks again!
~ April
0 Kudos