Field Calculator Expression Question (RePost)

4424
10
01-28-2016 09:01 AM
HOWARDWILLIAMS
New Contributor

Thank you to all who responded to this question earlier.  I am re-posting a more specific question and hopefully my code will be easier to understand.

So, I have number of feature classes in a .gdb that have tree counts per acre in each polygon by year.  I am iteratively unioning the features by year adding a field that is the sum of the previous tree count with the new tree count.

import arcpy
arcpy.CheckOutExtension("spatial")
arcpy.env.overwriteOutput=True
arcpy.env.workspace="C:\LPP\APS.gdb"
R1="R1ADS"
Dam="Damage"
years=['1999','2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013']
fields=['TPA_','Acres_','NoTrees_']
###R1+years(i)+Dam is the name of the feature in the .gdb that will be unioned
RangeYear=['1999_2000','1999_2001','1999_2002','1999_2003','1999_2004','1999_2005',
'1999_2006','1999_2007','1999_2008','1999_2009','1999_2010','1999_2011','1999_2012','1999_2013']
### RangeYear is a variable that I created for naming the unioned outfeature
#________________________________________________

###The statement below create first RangeYear feature to base iteration on in following loop.  Because only two years are being added it requires a simple Field Calculator Expression to sum the trees per acre per year which I was able to figure out.
arcpy.Union_analysis([R1+years[0]+Dam,R1+years[1]+Dam],R1+years[0]+"_"+years[1]+Dam)
for j in range(0,3):
    arcpy.AddField_management(R1+years[0]+"_"+years[1]+Dam,fields+RangeYear[0],"FLOAT","","","")

###I tried to but the statements below in the loop above by having the Field Calculator expressions in a list also, however
###the program would not allow me to iterate through that list so I plugged the expression into the parameters below and ran the tool one at a ###time.
arcpy.CalculateField_management(R1+years[0]+"_"+years[1]+Dam,fields[0]+RangeYear[0],'!TPA_1999!+!TPA_2000!',"PYTHON")
arcpy.CalculateField_management(R1+years[0]+'_'+years[1]+Dam,fields[0]+RangeYear[0],'!Shape_Area! * 0.00024710538',"PYTHON")
arcpy.CalculateField_management(R1+years[0]+'_'+years[1]+Dam,fields[0]+RangeYear[0],'!TPA_1999_2000!*!Acres_1999_2000!',"PYTHON")

###The loop below unions the remaining years the previous years with the next chronological year;
###adds three new field; calculates the new fields values and then move on to the next union.
for i in range(0,13) :
      arcpy.Union_analysis([R1+years[0]+"_"+years[i+1]+Dam,R1+years[i+2]+Dam],R1+years[0]+"_"+years[i+2]+Dam)
             for j in range(0,3):
                  arcpy.AddField_management(R1+years[0]+'_'+years[i+2]+Dam,fields+RangeYear[i+1],"FLOAT","","","")
                  arcpy.CalculateField_management(R1+years[0]+'_'+years[i+2]+Dam,fields, ????Expression????, "PYTHON")
    
###OK so the major crux here is that for TPA_1999_20XX, I need to add the previously unioned TPA_1999_20XX-1 to TPA_20XX.
###I have no idea how to do this.  I suspect that once I figure this out, the next two expressions will be evident.
####################################Thanks for reading, sorry for being such a hack programmer!####################

Field Calculator Expression Arcpy

Message was edited by: HOWARD WILLIAMS

0 Kudos
10 Replies
HOWARDWILLIAMS
New Contributor

Ahhggg!  For some reason when I hit post the indentations get all messed up!  I have no idea why it is doing this, please see if you can decifer what I am trying to do here.  Again I am sorry for this, I will attach the .txt file that has the code looking nice.

Thanks

0 Kudos
JakeSkinner
Esri Esteemed Contributor

Hi Howard,

Check out this thread about posting code:

DanPatterson_Retired
MVP Emeritus

And you seem to have not seen this post Code Formatting... the basics++

XanderBakker
Esri Esteemed Contributor

OK, let's post a small part of the code that only produces messages to see if I understand what you are trying to do:

def main():
##    import arcpy
##    arcpy.env.overwriteOutput=True
##    arcpy.env.workspace= r"C:\LPP\APS.gdb"

    fields = ['TPA_','Acres_','NoTrees_']
    expr = "'!TPA_{0}! + !TPA_{1}!','!Shape_Area! * 0.00024710538','!TPA_{2}! * !Acres_{2}!'"
    years = [str(year) for year in range(1999, 2014)]
    range_years = ['{0}_{1}'.format(years[0], year) for year in years[1:]]

    # initial union
    print "initial union"
    lst_union = ["R1ADS{0}Damage".format(y) for y in years[:2]]
    fc_out = "R1ADS{0}Damage".format(range_years[0])
    print lst_union
    print fc_out
    prev_union = fc_out

    # arcpy.Union_analysis(lst_union, fc_out)
    expr2 = expr.format(years[0], years[1], range_years[0])
    expressions = expr2.split(',')
    for j in range(0,3):
        fld = fields+range_years[0]
##        arcpy.AddField_management(fc_out, fields+range_years[0], "FLOAT")
##        arcpy.CalculateField_management(fc_out, fields+range_years[0], expressions, "PYTHON")
        print " - AddField", fld
        print " - CalcField", fld, expressions

    # other unions
    print "\nother unions"
    for y in years[2:]:
        index = years.index(y)
        lst_union = ["R1ADS{0}Damage".format(years[index-1]), "R1ADS{0}Damage".format(y)]
        lst_union = [prev_union, "R1ADS{0}Damage".format(y)]
        fc_out = "R1ADS{0}Damage".format(range_years[index-1])
        prev_union = fc_out
        print lst_union
        print fc_out
        expr2 = expr.format(years[index-1], y, range_years[index-1])
        expr3 = expr.format(range_years[index-2], y, range_years[index-1])
        expressions = expr2.split(',')
        expressions2 = expr3.split(',')

        # arcpy.Union_analysis(lst_union, fc_out)
        for j in range(0,3):
            fld = fields+range_years[index-1]
##            arcpy.AddField_management(fc_out, fld, "FLOAT")
##            arcpy.CalculateField_management(fc_out, fields, expressions, "PYTHON")
            print " - AddField", fld
            print " - CalcField", fld, expressions
            if j == 0:
                print "  or - CalcField", fld, expressions2

if __name__ == '__main__':
    main()

This yields the following output text:

initial union
['R1ADS1999Damage', 'R1ADS2000Damage']
R1ADS1999_2000Damage
 - AddField TPA_1999_2000
 - CalcField TPA_1999_2000 '!TPA_1999! + !TPA_2000!'
 - AddField Acres_1999_2000
 - CalcField Acres_1999_2000 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2000
 - CalcField NoTrees_1999_2000 '!TPA_1999_2000! * !Acres_1999_2000!'

other unions
['R1ADS1999_2000Damage', 'R1ADS2001Damage']
R1ADS1999_2001Damage
 - AddField TPA_1999_2001
 - CalcField TPA_1999_2001 '!TPA_2000! + !TPA_2001!'
  or - CalcField TPA_1999_2001 '!TPA_1999_2000! + !TPA_2001!'
 - AddField Acres_1999_2001
 - CalcField Acres_1999_2001 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2001
 - CalcField NoTrees_1999_2001 '!TPA_1999_2001! * !Acres_1999_2001!'
['R1ADS1999_2001Damage', 'R1ADS2002Damage']
R1ADS1999_2002Damage
 - AddField TPA_1999_2002
 - CalcField TPA_1999_2002 '!TPA_2001! + !TPA_2002!'
  or - CalcField TPA_1999_2002 '!TPA_1999_2001! + !TPA_2002!'
 - AddField Acres_1999_2002
 - CalcField Acres_1999_2002 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2002
 - CalcField NoTrees_1999_2002 '!TPA_1999_2002! * !Acres_1999_2002!'
['R1ADS1999_2002Damage', 'R1ADS2003Damage']
R1ADS1999_2003Damage
 - AddField TPA_1999_2003
 - CalcField TPA_1999_2003 '!TPA_2002! + !TPA_2003!'
  or - CalcField TPA_1999_2003 '!TPA_1999_2002! + !TPA_2003!'
 - AddField Acres_1999_2003
 - CalcField Acres_1999_2003 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2003
 - CalcField NoTrees_1999_2003 '!TPA_1999_2003! * !Acres_1999_2003!'
['R1ADS1999_2003Damage', 'R1ADS2004Damage']
R1ADS1999_2004Damage
 - AddField TPA_1999_2004
 - CalcField TPA_1999_2004 '!TPA_2003! + !TPA_2004!'
  or - CalcField TPA_1999_2004 '!TPA_1999_2003! + !TPA_2004!'
 - AddField Acres_1999_2004
 - CalcField Acres_1999_2004 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2004
 - CalcField NoTrees_1999_2004 '!TPA_1999_2004! * !Acres_1999_2004!'
['R1ADS1999_2004Damage', 'R1ADS2005Damage']
R1ADS1999_2005Damage
 - AddField TPA_1999_2005
 - CalcField TPA_1999_2005 '!TPA_2004! + !TPA_2005!'
  or - CalcField TPA_1999_2005 '!TPA_1999_2004! + !TPA_2005!'
 - AddField Acres_1999_2005
 - CalcField Acres_1999_2005 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2005
 - CalcField NoTrees_1999_2005 '!TPA_1999_2005! * !Acres_1999_2005!'
['R1ADS1999_2005Damage', 'R1ADS2006Damage']
R1ADS1999_2006Damage
 - AddField TPA_1999_2006
 - CalcField TPA_1999_2006 '!TPA_2005! + !TPA_2006!'
  or - CalcField TPA_1999_2006 '!TPA_1999_2005! + !TPA_2006!'
 - AddField Acres_1999_2006
 - CalcField Acres_1999_2006 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2006
 - CalcField NoTrees_1999_2006 '!TPA_1999_2006! * !Acres_1999_2006!'
['R1ADS1999_2006Damage', 'R1ADS2007Damage']
R1ADS1999_2007Damage
 - AddField TPA_1999_2007
 - CalcField TPA_1999_2007 '!TPA_2006! + !TPA_2007!'
  or - CalcField TPA_1999_2007 '!TPA_1999_2006! + !TPA_2007!'
 - AddField Acres_1999_2007
 - CalcField Acres_1999_2007 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2007
 - CalcField NoTrees_1999_2007 '!TPA_1999_2007! * !Acres_1999_2007!'
['R1ADS1999_2007Damage', 'R1ADS2008Damage']
R1ADS1999_2008Damage
 - AddField TPA_1999_2008
 - CalcField TPA_1999_2008 '!TPA_2007! + !TPA_2008!'
  or - CalcField TPA_1999_2008 '!TPA_1999_2007! + !TPA_2008!'
 - AddField Acres_1999_2008
 - CalcField Acres_1999_2008 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2008
 - CalcField NoTrees_1999_2008 '!TPA_1999_2008! * !Acres_1999_2008!'
['R1ADS1999_2008Damage', 'R1ADS2009Damage']
R1ADS1999_2009Damage
 - AddField TPA_1999_2009
 - CalcField TPA_1999_2009 '!TPA_2008! + !TPA_2009!'
  or - CalcField TPA_1999_2009 '!TPA_1999_2008! + !TPA_2009!'
 - AddField Acres_1999_2009
 - CalcField Acres_1999_2009 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2009
 - CalcField NoTrees_1999_2009 '!TPA_1999_2009! * !Acres_1999_2009!'
['R1ADS1999_2009Damage', 'R1ADS2010Damage']
R1ADS1999_2010Damage
 - AddField TPA_1999_2010
 - CalcField TPA_1999_2010 '!TPA_2009! + !TPA_2010!'
  or - CalcField TPA_1999_2010 '!TPA_1999_2009! + !TPA_2010!'
 - AddField Acres_1999_2010
 - CalcField Acres_1999_2010 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2010
 - CalcField NoTrees_1999_2010 '!TPA_1999_2010! * !Acres_1999_2010!'
['R1ADS1999_2010Damage', 'R1ADS2011Damage']
R1ADS1999_2011Damage
 - AddField TPA_1999_2011
 - CalcField TPA_1999_2011 '!TPA_2010! + !TPA_2011!'
  or - CalcField TPA_1999_2011 '!TPA_1999_2010! + !TPA_2011!'
 - AddField Acres_1999_2011
 - CalcField Acres_1999_2011 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2011
 - CalcField NoTrees_1999_2011 '!TPA_1999_2011! * !Acres_1999_2011!'
['R1ADS1999_2011Damage', 'R1ADS2012Damage']
R1ADS1999_2012Damage
 - AddField TPA_1999_2012
 - CalcField TPA_1999_2012 '!TPA_2011! + !TPA_2012!'
  or - CalcField TPA_1999_2012 '!TPA_1999_2011! + !TPA_2012!'
 - AddField Acres_1999_2012
 - CalcField Acres_1999_2012 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2012
 - CalcField NoTrees_1999_2012 '!TPA_1999_2012! * !Acres_1999_2012!'
['R1ADS1999_2012Damage', 'R1ADS2013Damage']
R1ADS1999_2013Damage
 - AddField TPA_1999_2013
 - CalcField TPA_1999_2013 '!TPA_2012! + !TPA_2013!'
  or - CalcField TPA_1999_2013 '!TPA_1999_2012! + !TPA_2013!'
 - AddField Acres_1999_2013
 - CalcField Acres_1999_2013 '!Shape_Area! * 0.00024710538'
 - AddField NoTrees_1999_2013
 - CalcField NoTrees_1999_2013 '!TPA_1999_2013! * !Acres_1999_2013!'

Is this what you are trying to do? Please have a good look at the union list and the calculation of the field TPA_ for the other unions.

HOWARDWILLIAMS
New Contributor

Thank you Xander,

I have had to take a break from this to do other work,  I certainly appreciate your help.

Howard

0 Kudos
HOWARDWILLIAMS
New Contributor

Xander,

Can you please explain what is going on with this line of code:

Line 09    range_years = ['{0}_{1}'.format(years[0], year) for year in years[1:]] 

The results do provide what I need however I do not understand how this code works. 

If you have time to explain it I would appreciate it.  Please do not trouble yourself though.

Thanks

Howard

0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi HOWARD WILLIAMS ,

The line you refer to is using "List comprehensions". To learn more about them I recommend List comprehensions... posted by Dan Patterson​.

In short, let's start a line before:

years = [str(year) for year in range(1999, 2014)]

This will generate a list called "years" with the following content:

['1999', '2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013']

This list "years" is used in the List comprehension:

range_years = ['{0}_{1}'.format(years[0], year) for year in years[1:]]

The result of this line is a list called "range_years" with this content:

['1999_2000', '1999_2001', '1999_2002', '1999_2003', '1999_2004', '1999_2005', '1999_2006', '1999_2007', '1999_2008', '1999_2009', '1999_2010', '1999_2011', '1999_2012', '1999_2013']

Let's take the line apart. We don't use the entire list of year but start at index 1 (the second element of the list)

print years[1:]

... returns:

['2000', '2001', '2002', '2003', '2004', '2005', '2006', '2007', '2008', '2009', '2010', '2011', '2012', '2013']

For each year in this part of the list (2000 until 2013) we use a string and a format command.

Example:

print '{0}_{1}'.format('hello', 'there')

Will return:

hello_there

So we have a string '{0}_{1}'and the string has a method called 'format' that allows us to pass two parameters 'hello' and 'there' and it will be formatted to 'hello_there'. {0} will be replaced by the first parameter and {1} by the second.

This is also done with the parameters years[0] and year. The first (years[0]) takes the first element of the list years (in this case '1999') and the second is the one that changes in the loop (varies from '2000' to '2013'). This creates the list of the year ranges we need in the process.

HOWARDWILLIAMS
New Contributor

Xander,

Thanks so much I have already learned a ton from you!  What a help you have been!  I have almost got it but am getting an error message saying "The value type is incompatible with the field type.  [TPA_1999_2000]" here is the code:  Any idea why?@Xandar Bakker

for i in range (0,15) :
    arcpy.CalculateField_management(R1+years+Dam,fields[0]+years,"!TPA1!+ !TPA2!+ !TPA3!","PYTHON")
##########Calculate Acres_Year
for i in range (0,15) :
    arcpy.CalculateField_management(R1+years+Dam,fields[1]+years,"!shape.area@acres!","PYTHON_9.3")
##########Calculate NoTrees_Year
for i in range (0,15) :
    expression="!"+fields[0]+years+"!"+"*"+"!"+fields[1]+years+"!"
    arcpy.CalculateField_management(R1+years+Dam,fields[2]+years,expression,"PYTHON")

#______________________________________________________________________________________________________________#
#Step 7.  Union former year to year following starting with 1999.  Add new fields.  Calcuate fields
# I was unable to figure out how to do this the following step in a loop so the code is being applied to each year.


RangeYear = ['{0}_{1}'.format(years[0], year) for year in years[1:]]

####1999-2000
exp="'!TPA_{0}! + !TPA_{1}!','!shape.area@acres!','!TPA_{2}! * !Acres_{2}!'"

for i in range (0,1):
    arcpy.Union_analysis([R1+years+Dam, R1+years[i+1]+Dam],R1+RangeYear+Dam)
    exp2= exp.format(years,years[i+1],RangeYears,RangeYears)
    expression=exp2.split(',')
    for j in range(0,3):
        arcpy.AddField_management(R1+RangeYears+Dam,fields+RangeYear,"FLOAT")
        print fields+RangeYear
        print expression
        arcpy.CalculateField_management(R1+RangeYears+Dam,fields+RangeYear,expression,"PYTHON")
0 Kudos
HOWARDWILLIAMS
New Contributor

Xander,

I think I figured it out when I call expression,  it places the expression inside double quotation marks.  However if I write the expression in without the double quotation marks it works.

exp="'!TPA_{0}!+!TPA_{1}!','!shape.area@acres!','!TPA_{2}! * !Acres_{2}!'"
exp2= exp.format(years[0],years[1],RangeYear[0],RangeYear[0])
expression=exp2.split(',')
arcpy.CalculateField_management(R1+RangeYear[0]+Dam,fields[0]+RangeYear[0],expression[0],"PYTHON")  #Does not work
arcpy.CalculateField_management(R1+RangeYear[0]+Dam,fields[0]+RangeYear[0],'!TPA_1999!+!TPA_2000!',"PYTHON") #Does work
0 Kudos