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 |
|
Solved! Go to Solution.
Hi @NoahLeimgruber ,
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[0]: [r[1], r[2], r[3]] 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[0]
# determine catchment area
catchment = SumAreaInRangeH(oidcurr, dct)
row[1] = 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][0]
h2 = dct[oidcurr][1]
sumarea = 0
for oid, lst in dct.items():
if oid != oidcurr and lst[0] > h1 and lst[1] < h2:
sumarea += lst[2]
return sumarea
if __name__ == '__main__':
main()
Hi @NoahLeimgruber ,
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?
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!
Hi @NoahLeimgruber ,
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?
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:
H1 refers to X and H2 to Y
by "Einzugsgeb" is meant the catchment area
Hi @NoahLeimgruber ,
Thanks for sharing. I will have a look and post back any results or questions that may arrise.
Hi @NoahLeimgruber ,
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[0]: [r[1], r[2], r[3]] 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[0]
# determine catchment area
catchment = SumAreaInRangeH(oidcurr, dct)
row[1] = 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][0]
h2 = dct[oidcurr][1]
sumarea = 0
for oid, lst in dct.items():
if oid != oidcurr and lst[0] > h1 and lst[1] < h2:
sumarea += lst[2]
return sumarea
if __name__ == '__main__':
main()
Hi @NoahLeimgruber ,
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.
I also notice that they are summing the same polygon areas.
What do you mean by that exactly?
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...