ArcGIS Field Calculator – Fixing Null Row Issues from Function

arcgis-desktoparcmapfield-calculatorpython-parser

Had a field that had some categories that didnt make sense to be listed alphabetically so wanted to add a preceding number to the text so they would be in the order I wanted. Ran it once and it worked on all but 1 of them so I thought maybe there was an extra space so went into the field to copy and paste the value. It was the same but I copied it anyway and then when I ran it again it caused the entire column to become null. Didnt have undo on so now have to go through the entire workflow. Why did this happen so I can avoid it in the future?

Expression:

func(!Hab_Class!)

Code Block:

def func(hab):
    if hab == 'Lowest':
        return '1. Lowest'
    elif hab == 'Marginal':
        return '2. Marginal'
    elif hab == 'Moderately High':
        return '3. Moderately High'
    elif hab == 'Highest':
        return '4. Highest'

Best Answer

If you're calculating into the same column that you're getting values from, you always run the risk of losing/messing up the values in that column.

In your case, you'd already calculated the column, so hab values that had already been changed did not match anything in your if: elif: statement and because you didn't explicitly return anything your function automatically returned None (standard python behaviour) and ArcGIS duly set the values to None.

Your best way to avoid this is to add a temporary column, run your calculation to populate the temp column then check and if everything is ok, calculate the original column from the temp column.

There's also an 'enable undo' toggle in the field calculator tool, but I've never used that.

Alternatively, ensure your expression returns something instead of None:

Code Block:

def func(hab):
    if hab == 'Lowest':
        return '1. Lowest'
    elif hab == 'Marginal':
        return '2. Marginal'
    elif hab == 'Moderately High':
        return '3. Moderately High'
    elif hab == 'Highest':
        return '4. Highest'
    else:
        return hab  # leave unmatched values as-is...

    # or instead of the else: clause
    # just return something before the end of the function e.g.
    return hab  # leave unmatched values as-is...

You could also use a dict.get:

Expression:

lookup.get(!Hab_Class!, !Hab_Class!)

Code Block:

lookup = {
    'Lowest': '1. Lowest',
    'Marginal': '2. Marginal',
    'Moderately High': '3. Moderately High',
    'Highest': '4. Highest'
}