2

Using ArcGIS 10.7 desktop.

I want to reclassify a land use field using Field Calculator. Grasslands are conditionally reclassified using a 'veg_type' field (Avena, or Bromus) and a CWHR land use field (grassland values = Annual Grassland, AGS, Perennial Grassland). All other values in the CWHR field should stay the same.

When I run the Python Parser syntax the Grassland_Reclass field returns "Avena Grassland" (gridcode = 1) for the assigned land use values, but also for grasslands categorized as "Bromus' (gridcode = 0). The default CWHR values are added, but the elif condition (gridcode = 0) is not returned. I've also tried with the veg_type field but I get the same result.

def Reclass(gridcode, CWHR_TYPE):
  if gridcode == 1 and CWHR_TYPE == "Annual Grassland" or CWHR_TYPE == "AGS" or CWHR_TYPE == "Perennial Grassland":
    return "Avena Grassland"
  elif gridcode == 0 and CWHR_TYPE == "Annual Grassland" or CWHR_TYPE == "AGS" or CWHR_TYPE == "Perennial Grassland":
    return "Bromus Grassland"  
  else:
    return CWHR_TYPE

Expression: Grassland_Reclass =

Reclass(!gridcode!, !CWHR_TYPE!)

enter image description here

2
  • 2
    Just an observation, the only effective value that defines the outcome is gridcode, given the rest to the right hand side is the same. Also, pyhon has in operator and it is great replacement for multiple ors and easier to read, e.g., CWHR_TYPE in ("Annual Grassland", "AGS", "Perennial Grassland")
    – fatih_dur
    Commented Aug 1, 2020 at 9:49
  • If you have a table of data, and you want to select all rows having some properties (e.g. CWHR_TYPE is "Annual Grassland") the correct language to use is SQL. Do not use python. Use SQL. SQL is quite literally, designed to do nothing but manage tables of data. Commented Aug 2, 2020 at 4:46

2 Answers 2

4

Logical operator precedence and order of operators is causing your issue. Try grouping your ors in parentheses:

e.g.

Wrong:

def Reclass(gridcode, CWHR_TYPE):
  if gridcode == 1 and CWHR_TYPE == "Annual Grassland" or CWHR_TYPE == "AGS" or CWHR_TYPE == "Perennial Grassland":
    return "Avena Grassland"
  elif gridcode == 0 and CWHR_TYPE == "Annual Grassland" or CWHR_TYPE == "AGS" or CWHR_TYPE == "Perennial Grassland":
    return "Bromus Grassland"
  else:
    return CWHR_TYPE

print(Reclass(0,"Annual Grassland"))
print(Reclass(1,"Annual Grassland"))
print(Reclass(0,"Perennial Grassland"))
print(Reclass(1,"Perennial Grassland"))

Output:

Bromus Grassland
Avena Grassland
Avena Grassland
Avena Grassland

Right:

def Reclass(gridcode, CWHR_TYPE):
    if gridcode == 1 and (CWHR_TYPE == "Annual Grassland" or CWHR_TYPE == "AGS" or CWHR_TYPE == "Perennial Grassland"):
        return "Avena Grassland"
    elif gridcode == 0 and (
            CWHR_TYPE == "Annual Grassland" or CWHR_TYPE == "AGS" or CWHR_TYPE == "Perennial Grassland"):
        return "Bromus Grassland"
    else:
        return CWHR_TYPE


print(Reclass(0, "Annual Grassland"))
print(Reclass(1, "Annual Grassland"))
print(Reclass(0, "Perennial Grassland"))
print(Reclass(1, "Perennial Grassland"))

Output:

Bromus Grassland
Avena Grassland
Bromus Grassland
Avena Grassland

Even better, use the in operator (thanks @fatih_dur):

Right:

def Reclass(gridcode, CWHR_TYPE):
    if gridcode == 1 and CWHR_TYPE in ("Annual Grassland", "AGS", "Perennial Grassland"):
        return "Avena Grassland"
    elif gridcode == 0 and CWHR_TYPE in ("Annual Grassland", "AGS", "Perennial Grassland"):
        return "Bromus Grassland"
    else:
        return CWHR_TYPE
2
  • Placing the parentheses around the CWHR values made the difference - thank you! (The binary grid code covers all CWHR land use features, not just the grasslands, which is why I needed to include the grassland classes to sort out.)
    – kent
    Commented Aug 1, 2020 at 18:52
  • 1
    Left to right evaluation isn't relevant here. The problem is due to the precedence of and and or. Commented Aug 2, 2020 at 8:43
3

What you are seeing is due to the fact that and takes precedence over or. a and b or c is the same as (a and b) or c and not a and (b or c), as you assumed.

As mentioned in the other answer, you can use parentheses to change the precedence (because parentheses have a higher precedence than either of and and or), or even better, use in. You can also turn your checks around, like this:

def Reclass(gridcode, CWHR_TYPE):
    if CWHR_TYPE not in ("Annual Grassland", "AGS", "Perennial Grassland") or gridcode not in (0, 1):
        return CWHR_TYPE
    return "Avena Grassland" if gridcode == 0 else "Bromus Grassland"
        

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.