Select to view content in your preferred language

Use Python to Reclass a Field Based on Multiple Input Fields

4595
6
08-02-2018 10:51 AM
ChristopherMatechik
Regular Contributor

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
Regular Contributor

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
Regular Contributor

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
Regular Contributor

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