Newly Added Field: Not being recognized in Python Function

1860
10
Jump to solution
07-13-2016 08:18 AM
PeterWilson
Regular Contributor

I've added a new field "CatchAreaKm2" (Double) to a File Geodatabase Table. I then create a list of fields of the table that will be used in an UpdateCursor. The problem that I have is that the newly added field is listed within the list of fields yet when I iterate through a sliced version of the fields (landuse) it doesn't recognize the newly added "CatchAreaKm2" field and I can't understand for the life of me why not. In order the get a list of the Landuse fields the index slice should be row[1:-1] yet if I use the following it skips the last landuse field ignoring the newly added field. in order to get the following to work I need to using the index slice row[1:]

Any help solving why the newly field is not being recognized will be appreciated.

  • [u'HydroID', u'Commercial_Forestry', u'Cultivated', u'Indigenous', u'Mines', u'Natural_Vegetation_Forest', u'Urban', u'Waterbodies', u'Wetlands', u'CatchAreaKm2']

Python: landuse_fields

# calculate percentage of landuse per watershed

def landuse_percentage(watershed, output_pivot):

    watershed_fields = ["HydroID", "Shape_Area"]

    valuedict = {r[0]: (r[1:]) for r in arcpy.da.SearchCursor(watershed, watershed_fields)}  # @UndefinedVariable

    arcpy.AddField_management(output_pivot, "CatchAreaKm2", "DOUBLE")

    landuse_fields = [f.name for f in arcpy.ListFields(output_pivot)[1:]]

    print(landuse_fields)

    with arcpy.da.UpdateCursor(output_pivot, landuse_fields) as upcur:  # @UndefinedVariable

        for row in upcur:

            keyvalue = row[0]

            if keyvalue in valuedict:

                arcpy.AddMessage("Processing Watershed {0}".format(keyvalue))

                # add catchment area km² to newly added field

                row[-1] = valuedict[keyvalue][0]/1000000

                for i, landuse in enumerate(row[1:]): # index slice not picking up newly added field

                    row = (row*(28*28))/(valuedict[keyvalue][0])*100

                    upcur.updateRow(row)

landuse_percentage(watershed, output_pivot)

Python: Code (Currently working)

# calculate percentage of landuse per watershed

def landuse_percentage(watershed, output_pivot):

    watershed_fields = ["HydroID", "Shape_Area"]

    valuedict = {r[0]: (r[1:]) for r in arcpy.da.SearchCursor(watershed, watershed_fields)}  # @UndefinedVariable

    arcpy.AddField_management(output_pivot, "CatchAreaKm2", "DOUBLE")

    landuse_fields = [f.name for f in arcpy.ListFields(output_pivot)[1:]]

    print(landuse_fields)

    with arcpy.da.UpdateCursor(output_pivot, landuse_fields) as upcur:  # @UndefinedVariable

        for row in upcur:

            keyvalue = row[0]

            if keyvalue in valuedict:

                arcpy.AddMessage("Processing Watershed {0}".format(keyvalue))

                # add catchment area km² to newly added field

                row[-1] = valuedict[keyvalue][0]/1000000

                for i, landuse in enumerate(row[1:-1]): # index slice should be

                    row = (row*(28*28))/(valuedict[keyvalue][0])*100

                    upcur.updateRow(row)

landuse_percentage(watershed, output_pivot)

Python: Code (Not working)

0 Kudos
1 Solution

Accepted Solutions
PeterWilson
Regular Contributor

Hi All

I solved it, I was correct that the index slice should be row[1:-1] what I had missed that the index starts at 0 and can be managed with an optional argument within Python Enumerate Function​.

# calculate percentage of landuse per watershed

def landuse_percentage(watershed, output_pivot):

    watershed_fields = ["HydroID", "Shape_Area"]

    valuedict = {r[0]: (r[1:]) for r in arcpy.da.SearchCursor(watershed, watershed_fields)}  # @UndefinedVariable

    arcpy.AddField_management(output_pivot, "CatchAreaKm2", "DOUBLE")

    landuse_fields = [f.name for f in arcpy.ListFields(output_pivot)[1:]]

    with arcpy.da.UpdateCursor(output_pivot, landuse_fields) as upcur:  # @UndefinedVariable

        for row in upcur:

            keyvalue = row[0]

            if keyvalue in valuedict:

                arcpy.AddMessage("Processing Watershed {0}".format(keyvalue))

                row[-1] = valuedict[keyvalue][0]/1000000

                for i, landuse in enumerate(row[1:-1], 1):

                    row = (landuse*(28*28))/(valuedict[keyvalue][0])*100

                    print("Index: {0}, Landuse: {1}, CatchAreaKm2: {2}, Percentage: {3}".format(i, landuse, row[-1], row))

                    upcur.updateRow(row)

landuse_percentage(watershed, output_pivot)

Thanks for all the help, from everyone.

View solution in original post

0 Kudos
10 Replies
NeilAyres
MVP Frequent Contributor

Sorry Peter,

What do you mean "doesn't recognize the newly added".

Has the AddField worked or not?

What error do you get if you access the field?

0 Kudos
PeterWilson
Regular Contributor

Hi Neil

The field is added and identified within the list, yet when I step into line 15 I should have to adjust the index slice row[1:] to row[1:-1] to exclude the added field from fields being updated.

0 Kudos
PeterWilson
Regular Contributor

Hi Dan Dan Patterson​ \ Luke Luke Pinner

Just wonder if either of you have any idea why my enumerate function isn't working as expected. The index slice should be row[1:-1] yet it doesn't work, only row[1:] works, which shouldn't as it would include the newly added "CatchAreaKm2" field.

0 Kudos
DanPatterson_Retired
MVP Esteemed Contributor

Slicing

>>> flds = [u'HydroID', u'Commercial_Forestry',...snip.., u'Urban', u'Waterbodies', u'Wetlands', u'CatchAreaKm2']

>>> flds[1:]

['Commercial_Forestry', ... snip..., 'Urban', 'Waterbodies', 'Wetlands', 'CatchAreaKm2']

>>> flds[1:-1]

['Commercial_Forestry', 'Cultivated',  ...snip... 'Urban', 'Waterbodies', 'Wetlands']

>>>

>>> flds[:-1]

['HydroID', 'Commercial_Forestry', ... snip..., 'Urban', 'Waterbodies', 'Wetlands']

lst, 1: slice from index 1 to end

2nd slice from 1 to everything except the last

3rd  slice from the start (index 0) except the last.

I am not quite sure why you need an enumerator... I will have to think... I tend not to use iterators, generators etc, but either to use the built-in array operations or variants of list comprehensions (ie set, dictionary comps) Do be aware that numpy has builtin iterators and generators which work best with arrays more so that their pure python equivalents.   Something else to write about now that I have thrown it out

PeterWilson
Regular Contributor

Hi Dan

Thanks for getting back to me. The reason for using the enumerator was to be able to update a specific list of fields within the UpdateCursor using the same formula without having to specify each index position (i.e. row[1], row[2]) etc. I solved the following by using the optional argument to specify the starting index number. The original post is under the following discusssion:

Data Access Module: Update Cursor (Not Updating Records)

0 Kudos
PeterWilson
Regular Contributor

Hi All

I solved it, I was correct that the index slice should be row[1:-1] what I had missed that the index starts at 0 and can be managed with an optional argument within Python Enumerate Function​.

# calculate percentage of landuse per watershed

def landuse_percentage(watershed, output_pivot):

    watershed_fields = ["HydroID", "Shape_Area"]

    valuedict = {r[0]: (r[1:]) for r in arcpy.da.SearchCursor(watershed, watershed_fields)}  # @UndefinedVariable

    arcpy.AddField_management(output_pivot, "CatchAreaKm2", "DOUBLE")

    landuse_fields = [f.name for f in arcpy.ListFields(output_pivot)[1:]]

    with arcpy.da.UpdateCursor(output_pivot, landuse_fields) as upcur:  # @UndefinedVariable

        for row in upcur:

            keyvalue = row[0]

            if keyvalue in valuedict:

                arcpy.AddMessage("Processing Watershed {0}".format(keyvalue))

                row[-1] = valuedict[keyvalue][0]/1000000

                for i, landuse in enumerate(row[1:-1], 1):

                    row = (landuse*(28*28))/(valuedict[keyvalue][0])*100

                    print("Index: {0}, Landuse: {1}, CatchAreaKm2: {2}, Percentage: {3}".format(i, landuse, row[-1], row))

                    upcur.updateRow(row)

landuse_percentage(watershed, output_pivot)

Thanks for all the help, from everyone.

View solution in original post

0 Kudos
DarrenWiens2
MVP Honored Contributor

Your enumerate 'i' still starts at 0, even though the list you're enumerating starts at 1.

>>> my_fields = [u'HydroID', u'Commercial_Forestry', u'Cultivated', u'Indigenous', u'Mines', u'Natural_Vegetation_Forest', u'Urban', u'Waterbodies', u'Wetlands', u'CatchAreaKm2']

... for i, landuse in enumerate(my_fields[1:]):

...    print (i,my_fields)

...  

(0, u'HydroID')

(1, u'Commercial_Forestry')

(2, u'Cultivated')

(3, u'Indigenous')

(4, u'Mines')

(5, u'Natural_Vegetation_Forest')

(6, u'Urban')

(7, u'Waterbodies')

(8, u'Wetlands')

>>> my_fields = [u'HydroID', u'Commercial_Forestry', u'Cultivated', u'Indigenous', u'Mines', u'Natural_Vegetation_Forest', u'Urban', u'Waterbodies', u'Wetlands', u'CatchAreaKm2']

... for i, landuse in enumerate(my_fields[1:-1]):

...    print (i,my_fields)

...  

(0, u'HydroID')

(1, u'Commercial_Forestry')

(2, u'Cultivated')

(3, u'Indigenous')

(4, u'Mines')

(5, u'Natural_Vegetation_Forest')

(6, u'Urban')

(7, u'Waterbodies')

PeterWilson
Regular Contributor

Hi Darren

I was busy posting my answer to my own question, when your reply came through. By specifying the starting number of the index I was able to solve it. Thanks for your reply.

0 Kudos
Luke_Pinner
MVP Regular Contributor

Sorry Peter, that was my bad, I missed the fact you were slicing your row list to start from the 2nd element. I've updated my answer in your other post - https://community.esri.com/message/620711#comment-620711

0 Kudos