Use Python to Reclass a Field Based on Multiple Input Fields

3900
6
08-02-2018 10:51 AM
ChristopherMatechik
New Contributor III

Hi everybody,

I have a field called 'Status' that I reclassify every evening so I can update our symbology on one of my web maps. I wrote a function in Arcade that works, but in the interest of automation I am trying to convert my scripts to Python so I can use them in model builder.

There are 9 fields that contribute to the calculation of the field status. They are:

Date_Found

MIN_Hatchling_Emergence_Date

Data_Type

Washout

Removed

Need_to_Check

Assigned_HS

SOH_yes_no

Treatment_Code!

I am trying to use the Calculate Field Tool. When I click verify it says the expression is valid. The code will run but it returns <null>  in the status filed for every feature. I'm not too familiar with Python. Does anybody have any suggestions? I found a few examples online, but they all reclasses based on one input feature.

I enter this in the expression box:

reclass(!Date_Found!,!MIN_Hatchling_Emergence_Date!,!Data_Type!,!Washout!,!Removed!,!Need_to_Check!,!Assigned_HS!,!SOH_yes_no!,!Treatment_Code!)

And this in the Code Block Box:

def reclass(Date_Found,Date_SOH,Nest_or_Crawl,Washout,Removed,Check,Assigned_HS,SOH,TTT):

    if Nest_or_Crawl == "Crawl":

        if (time.strftime("%d/%m/%Y"))-Date_Found>=7:

            return "Old Crawl"

        else:

            return "Recent Crawl"

    elif Washout=="Y":

        return "Washed Out"

    elif Removed=="Y":

        return "Removed"

    elif Check =="Y":

        return "Check"

    elif (Assigned_HS=="N" and

         (time.strftime("%d/%m/%Y"))-Date_Found>=70):

             return "Ready for Removal"

    elif (Assigned_HS=="N" and

         SOH=="Y" and  (time.strftime("%d/%m/%Y"))-Date_SOH>=3):

             return "Ready for Removal"

    elif Assigned_HS=="Y" and [(time.strftime("%d/%m/%Y"))-Date_Found>=70 or

         (SOH=="Y" and (time.strftime("%d/%m/%Y"))-Date_SOH>=3)]:

             return "Ready for HS"

    elif Date_Found>=45 or TTT=="9":

        return "Look for SOH"

    else:

        return "Incubating"

Thank you for your time.

0 Kudos
6 Replies
DanPatterson_Retired
MVP Emeritus

Can you provide a line or two for testing.  I stopped at the first time.strftime since I don't know what Date_Found would be (date? string representation of a date?) and you can't subtract from a string

ChristopherMatechik
New Contributor III

Sure. Thank you for your feedback. I'm in the field today but I can provide a few rows tomorrow morning when I'm back in the office.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

The expression may be valid syntactically, but that doesn't mean it will give expected results, or even run without errors.  I agree with Dan that something seems off with the date operations.  Also, the square brackets in your second to last elif might also be a problem.  Syntactically you can wrap a Boolean expression in a list comprehension, which is what you have done, but I don't think it is returning the results you expect.

XanderBakker
Esri Esteemed Contributor

Maybe you are looking for something like this:

def reclass(Date_Found,Date_SOH,Nest_or_Crawl,Washout,Removed,Check,Assigned_HS,SOH,TTT):
    if Nest_or_Crawl == "Crawl":
        if ((datetime.datetime.now()-Date_Found).days>=7):
            return "Old Crawl"
        else:
            return "Recent Crawl"
    elif Washout=="Y":
        return "Washed Out"
    elif Removed=="Y":
        return "Removed"
    elif Check =="Y":
        return "Check"
    elif (Assigned_HS=="N" and ((datetime.datetime.now()-Date_Found).days>=70)):
             return "Ready for Removal (1)"
    elif (Assigned_HS=="N" and SOH=="Y" and
            (datetime.datetime.now()-Date_SOH).days>=3):
             return "Ready for Removal (2)"
    elif Assigned_HS=="Y" and ((datetime.datetime.now()-Date_Found).days>=70 or
         (SOH=="Y" and (datetime.datetime.now()-Date_SOH).days>=3)):
             return "Ready for HS"
    elif (datetime.datetime.now()-Date_Found).days>=45 or TTT=="9":
        return "Look for SOH"
    else:
        return "Incubating"

I noticed that:

  • you were using a minus between a string (current date) and a possible date (Date_Found and Date_SOW)
  • you were comparing a boolean and a list
  • testing to see is a date is larger than an int

However, without knowing the actual cases it is still guessing.

ChristopherMatechik
New Contributor III

Thanks for the help! I'll try this first thing tomorrow when I get back to the office.

The general consensus seems to be that it was the date that was throwing the calculation off. If I understand correctly, using 

datetime.datetime.now()

to refer to the current date works better because it calls the current date in a date format, whereas I used

time.strftime("%d/%m/%Y")

which has no date value. Additionally, your code converts the difference in dates into the number of days, so then I can compare it to the integer.

I'm excited to try this. Thank you to everybody for your time. I'll let you know how it goes.

0 Kudos
ChristopherMatechik
New Contributor III

Thanks for your input. I'm in the field now but I will re-evaluate how I'm looking at the dates tomorrow.

0 Kudos