# Calculate Field with Python/ Arcade

1009
16
Jump to solution
11-25-2020 04:45 AM
Labels (1) New Contributor III

HI all!

I want to execute a Python/Arcade command in ArcGIS Calculate Field which gives me a result for the catchment area (table).
The command should select all IDs in the list that have an X-value greater than the ID to be calculated (Here ID 1) and a Y-value less than the ID to be calculated (Here ID 1).
From the selected IDs, the respective areas should then be summed up and saved to the catchment area field.

In this example, the X and Y values of IDs 2 and 3 fulfill the condition. Thus, the respective areas would be added together, which would result in 15. The result would be stored in the catchment area of ID 1.

Thank you very much for your help!

 ID X Y area catchment area 1 1000 2000 23 ? (15) 2 1034 1083 10 … 3 1599 1743 5 … 4 1403 2004 34
Tags (3)
1 Solution

Accepted Solutions by Esri Esteemed Contributor

It seems to be working: I did notice that there are some polygons that have -1 for the H1 and H2 values and many have an H2 values that is equal to H1 +1. When selecting only those polygons that are larger than H1 and smaller than H2, you will not get any resulting polygon and a catchment area of 0. Is that correct?

The code I used is:

``````def main():
# load arcpy
import arcpy

# set reference to the featureclass
fc = r'D:\GeoNet\CatchmentArea\Data.shp' # change this

# create dictionary with H values and areas
flds1 = ("OID@", "H1", "H2", "SHAPE@AREA")
dct = {r: [r, r, r] for r in arcpy.da.SearchCursor(fc, flds1)}

# start update cursor to write the catchment areas
flds2 = ("OID@", "Einzugsgeb")
with arcpy.da.UpdateCursor(fc, flds2) as curs:
for row in curs:
# read values
oidcurr = row
# determine catchment area
catchment = SumAreaInRangeH(oidcurr, dct)
row = catchment
curs.updateRow(row)

def SumAreaInRangeH(oidcurr, dct):
# function to determine catchment area
sumarea = -1
if oidcurr in dct:
# set reference values
h1 = dct[oidcurr]
h2 = dct[oidcurr]
sumarea = 0
for oid, lst in dct.items():
if oid != oidcurr and lst > h1 and lst < h2:
sumarea += lst
return sumarea

if __name__ == '__main__':
main()``````
16 Replies by Esri Esteemed Contributor

I probably would advise you to use Python for this one and use a dictionary to store the values and easy access, although I wouldn't do this using a Field Calculation (preferably, I would use a standalone script). With Arcade you would probably end up using multiple requests on the data which would result in longer processing times.

However, is this "static" data or is this data dynamic and requires an update of this logic when data is edited? In that case I would probably go for an attribute rule using Arcade.

Just to be clear... when you calculate the catchment area for ID 1 you don't include the area of ID 1 in the result, right? New Contributor III

Hello @XanderBakker

Thank you very much for your answer and your suggestions! Unfortunately I'm a **bleep** beginner when it comes to coding so I don't understand exactly what you mean in the first section.

The data is "static".

and yes that is correct, i don't want to include the area of ID 1 in the calculation

Thank you again! by Esri Esteemed Contributor

I could write some code to do this, but it would be easier to have some (dummy) data with the same schema to test with. Any chance that you could share some (dummy) data for this? New Contributor III

Thank you so much, you are absolutely amazing!

I' ve created a WeTranfer link with the data inside because I could not upload the file here because it is bigger than 5MB:

https://we.tl/t-euedapBzW8

H1 refers to X and H2 to Y

by "Einzugsgeb" is meant the catchment area by Esri Esteemed Contributor

Thanks for sharing. I will have a look and post back any results or questions that may arrise. by Esri Esteemed Contributor

It seems to be working: I did notice that there are some polygons that have -1 for the H1 and H2 values and many have an H2 values that is equal to H1 +1. When selecting only those polygons that are larger than H1 and smaller than H2, you will not get any resulting polygon and a catchment area of 0. Is that correct?

The code I used is:

``````def main():
# load arcpy
import arcpy

# set reference to the featureclass
fc = r'D:\GeoNet\CatchmentArea\Data.shp' # change this

# create dictionary with H values and areas
flds1 = ("OID@", "H1", "H2", "SHAPE@AREA")
dct = {r: [r, r, r] for r in arcpy.da.SearchCursor(fc, flds1)}

# start update cursor to write the catchment areas
flds2 = ("OID@", "Einzugsgeb")
with arcpy.da.UpdateCursor(fc, flds2) as curs:
for row in curs:
# read values
oidcurr = row
# determine catchment area
catchment = SumAreaInRangeH(oidcurr, dct)
row = catchment
curs.updateRow(row)

def SumAreaInRangeH(oidcurr, dct):
# function to determine catchment area
sumarea = -1
if oidcurr in dct:
# set reference values
h1 = dct[oidcurr]
h2 = dct[oidcurr]
sumarea = 0
for oid, lst in dct.items():
if oid != oidcurr and lst > h1 and lst < h2:
sumarea += lst
return sumarea

if __name__ == '__main__':
main()`````` by Esri Esteemed Contributor

Looking a bit closer to the results I notice that in the Northern part there are some polygons with a huge catchment area. I also notice that they are summing the same polygon areas. If this is about catchments I don't think that this is hydrologically correct, but maybe the calculation has a different purpose. New Contributor III

I also notice that they are summing the same polygon areas.

What do you mean by that exactly? New Contributor III

First of all thank you for your work and your help!

I did notice that there are some polygons that have -1 for the H1 and H2 values and many have an H2 values that is equal to H1 +1. When selecting only those polygons that are larger than H1 and smaller than H2, you will not get any resulting polygon and a catchment area of 0. Is that correct?

Yes that's right, something is not 100% correct.
I just realized that it makes more sense if the H1 or H2 value can also be the same as the ID to be calculated.
So greater and equal than H1 and less and equal than H2. (not greater than H1 and less than H2)
This solves the problem with the 0 values, because at least the own area is included.

I don't understand why some attributes have a -1 value. but we lets ignore that... 