By Iracambi


2018-04-05 18:20:09 8 Comments

I have a classified raster with a class value that is a very long concatenated string name (Class_Name below). I'm trying to use arcpy to generate integer labels ranging from 1-24 (which are the third concatenated sub-group in these long strings). Here's an example of a previous (manually manipulated) similar raster attribute table. enter image description here

So far I've been manually using search criteria in ERDAS to find classes belonging to the same group such as:

$"Class_Names" contains "-14.01-" or $"Class_Names" contains "-14.02-" or $"Class_Names" contains "-14.03-"

I've tried using the following code (as a trial for the first two classes) with LIKE in a for loop with UpdateCursor, but I get a syntax error for my LIKE statement.

in_table = 'l12wm_agsup02.img'
field_names = ['Class_Name', 'crop']
with arcpy.da.UpdateCursor(in_table, field_names) as cursor:
    for row in cursor:
        if row[0] 'LIKE \'1.%\'':
            row[1] = 1
        elif row[0] 'LIKE \'2.%\'':
            row[1] = 2
        cursor.updateRow(row)

I've looked at Using LIKE clause in update cursor gives syntax error? and https://community.esri.com/thread/87848 but can't figure out how to use LIKE in the if else statements instead as a where clause in UpdateCursor.

I'm using ArcMap 10.5, Python 2.7

4 comments

@ahmadhanb 2018-04-05 19:26:11

You can parse your text based on dash (-) to split the text and select the 3rd number to convert it to integer. Try the following python code in your field calculator:

def select(f):
    if f == ' ':
        return 0
    else:
        txt = f.split("-")[2]
        digit = int(round(float(txt),0))
        return digit

The above code assumes all the column of Class_Name is filled with information with the same structure. If the field is empty of text, it will return zero (0). However, I used round() function to round the class to the nearest whole number in case you have something like 4.98, it will return 5 instead of 4. But, if you want to truncate the digit numbers, you can simply change the line:

digit = int(round(float(txt),0))

to:

digit = int(float(txt))

enter image description here

Here is sample output:

enter image description here

@BERA 2018-04-05 18:46:16

You can use the in operator, for example:

with arcpy.da.UpdateCursor(in_table, field_names) as cursor:
    for row in cursor:
        if '1.' in row[0]:
            row[1] = 1
...

And instead of writing 24 if statements you can use a dictionary:

d = {'1.':1, '2.':2, '3.':3} #add all values here

with arcpy.da.UpdateCursor(in_table, field_names) as cursor:
    for row in cursor:
        for key in d:
            if key in row[0]:
                row[1]=d[row[0]]
                cursor.updateRow(row)

But this wont work since '2.' is in both '12.' and '22.' so you can do:

row[1] = row[0].split('-')[2].split('.')[0]

@Iracambi 2018-04-05 19:48:13

Thanks for this code. I ran your first block of code and replaced the second to last line with your second block of code. For some reason, it didn't generate a value for half of the records and I can't find a pattern. Those that worked: 2.0, 13.01, 13.06, 11.0, 11.5, and 11.0. Those that didn't: 4.05, 5.03, 14.03, 5.01, 6.0, 6.04, 6.02, 7.0, 6.05.

@BERA 2018-04-05 19:51:03

You need to add those to the dictionary. Use @Aarons answer instead

@Aaron 2018-04-05 19:18:33

I would isolate the class you are after rather than searching for it. Then, simply assign row[1] that isolated value. For example:

in_table = 'l12wm_agsup02.img'
field_names = ['Class_Name', 'crop']
with arcpy.da.UpdateCursor(in_table, field_names) as cursor:
    for row in cursor:
        row[1] = row[0].split("-")[2].split(".")[0]
        cursor.updateRow(row)

@Iracambi 2018-04-06 22:09:12

Thank you Aaron, that worked like a charm! I forgot to mention that for some rows, 'Class_Name' was empty and one row would always be 'Unclassified'. I received an error something along the lines of "Index out of range" and so I added an if/elif/else to leave these as they were.

@Hornbydd 2018-04-05 18:41:11

This does not have to be done in a python script, it can be done simpler by using the calculate field tool as shown below:

Tool

If you want to run this as python the code would be:

arcpy.CalculateField_management("myRaster","crop","cropnumber( !class! )","PYTHON_9.3","""def cropnumber(s):/n  if s.find("-1.") != -1:/n    return 1/n  elif s.find("-2.") != -1 :/n    return 2/n  else:/n    return -999""")

Related Questions

Sponsored Content

2 Answered Questions

[SOLVED] Switching from Nested Search Cursors to Dictionaries

1 Answered Questions

[SOLVED] For loop within for loop with ArcPy cursor?

0 Answered Questions

2 Answered Questions

[SOLVED] How to run for loop with unique values

2 Answered Questions

[SOLVED] Saving output in ArcPy For-Loop?

2 Answered Questions

[SOLVED] arcpy: For loop to sequence Processing of two items in list using ArcPy?

  • 2018-02-12 14:06:02
  • maycca
  • 304 View
  • 2 Score
  • 2 Answer
  • Tags:   arcpy for-loop

1 Answered Questions

[SOLVED] For Loop not looping correctly - ArcPy

1 Answered Questions

[SOLVED] Using Update Cursor in a double for loop in arcpy

2 Answered Questions

[SOLVED] Randomly select a record to update using arcpy.da.UpdateCursor

Sponsored Content