Select to view content in your preferred language

"IndexError: list index out of range" - when trying to Update Layer in ArcPy

3403
10
10-05-2011 03:07 PM
KateNewell
Deactivated User
Hi!
I am trying to run (what I thought) was a very simple script that updates the symbology in a Layer File based on another layer file. Being very new to Python, I "lifted" some example code straight from the ArcGIS10 help ( http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#/UpdateLayer/00s30000003p000000/ )
The layer file to be updated in my map document is part of a grouped layer file within a grouped layer file.
I keep getting an IndexError and I have no idea why!?! There is only one dataframe (Layers). Any help is greatly appreciated!

Here is my code:

import arcpy
mxd = arcpy.mapping.MapDocument(r"N:\Templates\v10\Base Maps\A_Portrait.mxd")
df = arcpy.mapping.ListDataFrames(mxd, "Layers")[0]
updateLayer = arcpy.mapping.ListLayers(mxd, "Base Map Layers\Bay, Lakes & Streams", df)[0]
sourceLayer = arcpy.mapping.Layer(r"N:\Users\ke\Bay, Lakes & Streams.lyr")
arcpy.mapping.UpdateLayer(df, updateLayer, sourceLayer, True)
mxd.save()
del mxd, sourceLayer


and this is the error message that I get:
====
>>>
Traceback (most recent call last):
File "N:\Users\ke\ArcPyMapping\UpdateLayerFile.py", line 4, in <module>
updateLayer = arcpy.mapping.ListLayers(mxd, "Base Map Layers\Bay, Lakes & Streams", df)[0]
IndexError: list index out of range
Tags (2)
0 Kudos
10 Replies
ChrisSnyder
Honored Contributor
Since you are specifying exctly what layer you are interested in ("Base Map Layers\Bay, Lakes & Streams"), try leaving the [0] index off. The [0] being a refrence to the 1st item in a list, but this time you are only expecting one item anyway...

So instead of:
updateLayer = arcpy.mapping.ListLayers(mxd, "Base Map Layers\Bay, Lakes & Streams", df)[0]
try
updateLayer = arcpy.mapping.ListLayers(mxd, "Base Map Layers\Bay, Lakes & Streams", df)


If that idea doesn't work try:
updateLayer = arcpy.mapping.ListLayers(mxd, r"Base Map Layers\Bay, Lakes & Streams", df)[0]
instead of
updateLayer = arcpy.mapping.ListLayers(mxd, "Base Map Layers\Bay, Lakes & Streams", df)[0]

Since Python doesn't like the "\" symbol... You need to either use "\\", "/", or my favorite r"\".

Also, I have seen weird things happen then map layers contain special characters such as "&".

Hope something here helps.
0 Kudos
KateNewell
Deactivated User
Thanks for the reply Chris.
Unfortunatly none of that seemed to work.  When I added \\ or r"\", the same message appeared.
However when I removed the [0] from line four, I got a totally new error message (which is even more confusing!):

Traceback (most recent call last):
  File "N:\Users\ke\ArcPyMapping\UpdateLayerFile.py", line 6, in <module>
    arcpy.mapping.UpdateLayer(df, updateLayer, sourceLayer, True)
  File "C:\Program Files\ArcGIS\Desktop10.0\arcpy\arcpy\utils.py", line 181, in fn_
    return fn(*args, **kw)
  File "C:\Program Files\ArcGIS\Desktop10.0\arcpy\arcpy\mapping.py", line 1458, in UpdateLayer
    assert isinstance(update_layer, Layer)
AssertionError
0 Kudos
ChrisSnyder
Honored Contributor
Try renaming your layer to some simple name that doesn't have a & or \ symbol in it (like "mylayer"), and then try running the code like

updateLayer = arcpy.mapping.ListLayers(mxd, "mylayer", df)[0]

Does that work? If so, my guess is that arcpy doesn't like the \ or & symbol in your layer name...
0 Kudos
KateNewell
Deactivated User
😞
Still no luck.  Changed it to remove all the & and \ and the same error message persisted.
Thank you so much for the suggestions and warnings though....
Hmmmm....
0 Kudos
MarcNakleh
Regular Contributor
Hello Kate,

I'm no expert on arcpy's mapping module, but I couldn't help myself!

Your first and second error messages seem consistent to me: your code dies the first time on the arcpy.mapping.ListLayers call, which returns a list of layers that suit the filter, or an empty list '[]' if no results are found. I think your filter is returning an empty list (no values found), and so the function is trying to return the first element of your empty list, which kills it with an IndexError.
[][0] = DEAD

Then, by removing the [0], the function successfully passes on the empty list to the arcpy.mapping.UpdateLayer, which dies because it's being handed an empty list to work on.
arcpy.mapping.UpdateLayer(df, [], sourceLayer, True) = DEAD


I would recommend calling arcpy.mapping.ListLayers with the mxd and no filter, to see what name is being assigned to your layer. The List methods in arcpy are relatively fickle and need an exact match of the value being searched for, or at lest wildcards around them.

For example: shapethingy.shp will not appear under ListFeatureClasses(filter) if filter = 'shapethingy', but but will if filter = 'shapethingy*' or 'shapethingy.shp'

In fact, if this is your only layer, you don't even need to add in a filter: just call the layer directly by name in your other functions (since the only thing being passed around by ListLayers is a string, not an object)
arcpy.mapping.UpdateLayer(df, "LAYERS", sourceLayer, True)


I hope this helps!
0 Kudos
KateNewell
Deactivated User
Well, I finally got it to work, and the trick was putting it into a "for" loop. I still really don't understand the whole index thing, and I'm very new to Python, but this was the only way I could force it to find "Bay, Lakes & Streams"
When I take the [0] off, it would still fail.
Here is the code that works:


import arcpy
mxd = arcpy.mapping.MapDocument(r"N:\Templates\v10\Neighborhood Templates\York_NhoodMap.mxd")
df = arcpy.mapping.ListDataFrames(mxd)[0]
updateLayer = arcpy.mapping.ListLayers(mxd, r"Bay, Lakes & Streams", df)[0]
sourceLayer = arcpy.mapping.Layer(r"N:\Users\ke\BayLake.lyr")
for lyr in arcpy.mapping.ListLayers(mxd, "Bay, Lakes & Streams", df):
    arcpy.mapping.UpdateLayer(df, updateLayer, sourceLayer, False)
    mxd.save()
del mxd, sourceLayer


Thanks for everyones tips and tricks : )
0 Kudos
JeffBarrette
Esri Regular Contributor
When using List functions in arcpy.mapping you will always need to use the index number at the end:

myLayer = arcpy.mapping.ListLayers(mxd, "filter")[0]

This will return a layer object

myLayer = arcpy.mapping.ListLayers(mxd, "filter")[0]

This will return a Python list object

Also - there way most likely a typo in your filter.  Try using wildcard.

myLayer = arcpy.mapping.ListLayers(mxd, "Bay, Lakes*")[0]

Jeff
0 Kudos
KateNewell
Deactivated User
Jeff-
So, being new to Python...  What is the difference between a Layer Object and Python List Object.
I'm not seeing anything different in your two lines that you posted that would differentiate between the two?
0 Kudos
KateNewell
Deactivated User
Jeff (while I got ya here ; )
If I used the index of [0], isn't this just calling the first returned object in the list?  My "Bays, Lakes & Streams" grouped layer file is way at the bottom of my table of contents...which I would think would mean that instead of [0] I would be calling [21], which when I ran the "Longname" command and counted it's place, that is where it was...
Thanks for your help.  I did attend a conference where you were doing hands-on ArcPy.mapping workshop almost a year ago in Tacoma, unfortunately we only just finally got 10 installed so I'm just now trying to dive into using ArcPy.mapping.
0 Kudos