Why is list index out of range here but not here?

6526
12
Jump to solution
09-16-2018 11:53 PM
LindsayRaabe_FPCWA
Occasional Contributor III

The code below seems to function correctly most of the time except when running through a situation where line 43 is False (no extent updates based on this layer) and Line 51 is True (1+ feature in this layer), meaning Line 54 is also True (extent set at Line 22 should still match extent at Line 52). 

What I'm not understanding is 2 things:

1. Why is it running through the elif at Line 61 when the condition should be False (as per Line 54 being True)

2. Why when it does run through the elif at Line 61 I get the below Trackback error about the list Index being out of range when it works elsewhere in the same manner?

Hope that all makes sense!

import arcpy
from arcpy import env, mapping
from bisect import bisect

#input parameters;
Plantation = arcpy.GetParameter(0)
ForestID = arcpy.GetParameter(1)
CommonName = arcpy.GetParameter(2)
PYear = arcpy.GetParameter(3)
OpCode = arcpy.GetParameter(4)

#variables;
title1 = Plantation + " PLANTATION"
title2 = Plantation + "\r\nPLANTATION"
title3 = Plantation + " (" + CommonName + ")"
title4 = Plantation + " P" + PYear + " AREA STATEMENT"
mxd = mapping.MapDocument("CURRENT")
elements = mapping.ListLayoutElements(mxd)
layers = mapping.ListLayers(mxd)
HTL_layer_list = ["Entered In GeoMaster", "Entered In GeoMaster Archive"]
dflist = arcpy.mapping.ListDataFrames(mxd, "")
orig_ext = dflist[0].extent
new_exp = "PLANTATION = '" + Plantation + "'"
new_sur_exp = "PLANTATION <> '" + Plantation + "'"
as_new_exp = "EnteredInGeoMaster IS NOT NULL AND Plantation = '" + Plantation + "'"
opcode_exp1 = "Entered_In_GeoMaster IS NOT NULL AND Ops_Code = '" + OpCode + "'"
opcode_exp2 = "Ops_Code = '" + OpCode + "'"
scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000]

if mxd.title <> ("Cutting Returns Entered in GeoMaster"):

    ###other code here###

elif mxd.title == ("Cutting Returns Entered in GeoMaster"):

    mxd.activeView = "Page_Layout"
    
    for lyr in layers:
        if lyr.name == "Entered In GeoMaster":
            lyr.definitionQuery = opcode_exp1
            arcpy.AddMessage(lyr.name + " definition query updated")
            EIGfeature_count = arcpy.GetCount_management(lyr)[0]
            if EIGfeature_count > 0:
                ext = lyr.getExtent() #gets the new extent of the Entered In GeoMaster layer
                dflist[0].extent = ext #applies the Entered In GeoMaster layer extent to the dataframe
                    
        elif lyr.name == "Entered In GeoMaster Archive":
            lyr.definitionQuery = opcode_exp2
            arcpy.AddMessage(lyr.name + " definition query updated")
            EIGAfeature_count = arcpy.GetCount_management(lyr)[0]
            if EIGAfeature_count > 0:
                current_ext = dflist[0].extent

                if current_ext == orig_ext:
                    ext = lyr.getExtent() #gets the new extent of the Entered In GeoMaster layer
                    dflist[0].extent = ext #applies the Entered In GeoMaster layer extent to the dataframe
                    oldscale = dflist[0].scale # Get scale of dataframe
                    newscale = scalelist[bisect(scalelist, oldscale)] # bisect old scale to get new scale
                    dflist[0].scale = newscale # Apply new scale to dataframe

                elif current_ext <> orig_ext:
                    # get current map extent
                    xmin, xmax = dflist[0].extent.XMin, dflist[0].extent.XMax
                    ymin, ymax = dflist[0].extent.YMin, dflist[0].extent.YMax
                    # loop through def query layer extents and create one extent to fit them all
                    lyr_ext = lyr.getExtent()
                    if lyr_ext.XMin < xmin:
                        xmin = lyr_ext.XMin
                    if lyr_ext.YMin < ymin:
                        ymin = lyr_ext.YMin
                    if lyr_ext.XMax > xmax:
                        xmax = lyr_ext.XMax
                    if lyr_ext.YMax > ymax:
                        ymax = lyr_ext.YMax
                    # set df extent to new extent
                    dflist[0].extent = arcpy.Extent(xmin, ymin, xmax, ymax)
                    oldscale = dflist[0].scale # Get scale of dataframe
                    newscale = scalelist[bisect(scalelist, oldscale)] # bisect old scale to get new scale
                    dflist[0].scale = newscale # Apply new scale to dataframe

        elif lyr.name == "PlantationsHarvestPlan_OperationsPlanner_WA":
            lyr.definitionQuery = new_exp
            arcpy.AddMessage(lyr.name + " definition query updated")‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
Traceback (most recent call last):
 File "W:\Mapping\ToolboxPythonCodes\SCRIPTS\Update Definition Queries.py", line 78, in <module>
 newscale = scalelist[bisect(scalelist, oldscale)] # bisect old scale to get new scale
IndexError: list index out of range

For reference, the aim here is to updated the definition queries on 2 layers in an open MXD, check for features in each layer and zoom the extent to view all the features in both layers before stepping the scale up (using bisect) to the next round scale in the list. 

Lindsay Raabe
GIS Officer
Forest Products Commission WA
Tags (4)
0 Kudos
1 Solution

Accepted Solutions
DanPatterson_Retired
MVP Emeritus
from bisect import bisect

scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000]

oldscale = 404659.559547

newscale = scalelist[bisect(scalelist, oldscale)]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-25-e09e51ee6bfc> in <module>()
----> 1 newscale = scalelist[bisect(scalelist, oldscale)]

IndexError: list index out of range

# ---- now add 500,000 to the end
scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000, 500000]

oldscale = 404659.559547

newscale = scalelist[bisect(scalelist, oldscale)]

newscale
Out[29]: 500000

lets rule out that problem first

View solution in original post

12 Replies
DanPatterson_Retired
MVP Emeritus

What is it supposed to do if line 51 has a count of zero in line 51?

if EIGAfeature_count <> 0

0 Kudos
LindsayRaabe_FPCWA
Occasional Contributor III

It was intended to just skip that section of code if it didn't meet the count criteria (no features so no need to apply the layer extent to the data frame extent). I assumed that if it didn't meet that criteria it would just move on to the next valid bit of code instead or needing an ELIF. Have I figured that incorrectly?

Lindsay Raabe
GIS Officer
Forest Products Commission WA
0 Kudos
VinceAngelo
Esri Esteemed Contributor

GetCount returns a result array, not a count.  You need to retrieve the first element of that result array.

EIGAfeature_count = arcpy.GetCount_management(lyr)[0]

or

if EIGAfeature_count[0] > 0:

- V

LindsayRaabe_FPCWA
Occasional Contributor III

Thanks Vince for the tip. I've updated the original code snippet so hopefully I have that correct now. This still isn't helping the "list index out of range" error though at line 78. 

Lindsay Raabe
GIS Officer
Forest Products Commission WA
0 Kudos
DanPatterson_Retired
MVP Emeritus

throw a print statement before this line

newscale = scalelist[bisect(scalelist, oldscale)]

and  print scalelist and oldscale… one of the two is causing the error

and the line numbers don't match up anymore.  Do yours differ from those that are posted in the thread?

0 Kudos
LindsayRaabe_FPCWA
Occasional Contributor III

I've eliminated a big chunk of code that doesn't apply to this MXD so the lines are different from the original but I've been trying to factor that into my post/responses. Still looks correct to me though here?

I added in the print statements and this is the result when running a query where EIG = 0 and EIGA > 0 (sorry if I'm formatting this wrong - trying to break it up into the info/error sections). 

Executing: UpdateDefinitionQueries "Lake Muir 2" LM2 # # MLM7AFC
Start Time: Wed Sep 19 08:48:54 2018
Running script UpdateDefinitionQueries...
Entered In GeoMaster definition query updated
Entered In GeoMaster Archive definition query updated
scalelist: [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000]
old scale: 404659.559547
Failed script UpdateDefinitionQueries...
Traceback (most recent call last):
 File "W:\Mapping\ToolboxPythonCodes\SCRIPTS\Update Definition Queries.py", line 78, in <module>
 newscale = scalelist[bisect(scalelist, oldscale)] # bisect old scale to get new scale
IndexError: list index out of range
Failed to execute (UpdateDefinitionQueries).
Failed at Wed Sep 19 08:49:05 2018 (Elapsed Time: 10.25 seconds)
Lindsay Raabe
GIS Officer
Forest Products Commission WA
0 Kudos
DanPatterson_Retired
MVP Emeritus
from bisect import bisect

scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000]

oldscale = 404659.559547

newscale = scalelist[bisect(scalelist, oldscale)]
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-25-e09e51ee6bfc> in <module>()
----> 1 newscale = scalelist[bisect(scalelist, oldscale)]

IndexError: list index out of range

# ---- now add 500,000 to the end
scalelist = [5000, 7500, 10000, 12500, 20000, 25000, 30000, 40000, 50000, 60000, 70000, 75000, 80000, 90000, 100000, 500000]

oldscale = 404659.559547

newscale = scalelist[bisect(scalelist, oldscale)]

newscale
Out[29]: 500000

lets rule out that problem first

LindsayRaabe_FPCWA
Occasional Contributor III

That makes sense and works (insert face plant here). The part that I must have been getting hung up on though is the desire for this to be returning a typical scale concentrated on a small area (i.e. 1:20,000), meaning that the logic I've used to get the map to focus on the grouped features isn't working as expected. 

Fore example. Before running the script, the map is focused on a selection of polygons in one location (EIG > 0 and EIGA = 0). I run this script to change the definition query to look at a different selection of polygons in a different location (where EIG = 0 and EIGA > 0). The code should examine the if query at Line 43 as False and skip to the next ELIF (Line 47) resulting in an unchanged dataframe extent (at this point). 

Next it should examine the if EIGA > 0 (Line 51) as TRUE then set the current extent variable. Line 54 sees the current extent compared to the original extent (should result in TRUE) and proceed to Line 55. It would apply the layer extent to the dataframe and step up to the next in the list. That should be the end of it but for some reason it is progressing through to the elif at Line 61 and finding that TRUE. I would expect this to be FALSE because the current_ext and orig_ext variables are unchanged (to my knowledge) despite the dataframe extent being updated so should result in no further action being taken. 

What actually seems to be happening is the code is running the ELIF (Line 61) as TRUE and comparing the min/max values from the old extent and the new extent resulting in a huge scale. This should only be getting run if there are new features in both layers which will be similarly geolocated. This does work as expected when both layers > 0. 

Lindsay Raabe
GIS Officer
Forest Products Commission WA
0 Kudos
DanPatterson_Retired
MVP Emeritus

Lindsay all I can suggest at this point is.

you have 2 parameters and 2 conditions each? = 0 and > 0

(a == 0) and (b == 0)

(a == 0) and (b > 0)

(a > 0) and (b == 0)

(a > 0) and (b > 0)

Code separately for each section, and check the logic.  Put conditionals within brackets as I have shown, and if possible check for both conditions rather than one at a time if applicable.

And future proof yourself... python 3 is upon you soon

a = 0; b = 1
a <> b
  File "<ipython-input-44-7450b63d9fd5>", line 1
    a <> b       ^SyntaxError: invalid syntax

a != b
True