Printing the highest value between a range of values of a field

578
11
Jump to solution
06-11-2021 07:00 AM
Poncio
by
New Contributor II

I'm completly new with python and wanted to do this little project that would be very useful. What I want to do in the end is having a little window pop up and showing the highest value of a field but only for a specific range of values, like between 1000 and 2000. Here's an example:

Field1
1001
1002
1003
2002
2005
3001
3003
3008

What I need in the end is a list like this (but for now I'd be happy to just print out the right values):

Zone1 = 1003

Zone2 = 2005

Zone3 = 3008

 

With advice and code from another place I managed to write this

 

import arcpy
fc = 'C:\..............\Einzelpunkt.shp'
fields = ['Identifika']
#setting up the max value variables
Zone1=0
Zone2=0

# For each row in the attribute table, use if statements
# to determine which category it is in and if it is bigger
# than the current max value for that category, update the
# max value variable
with arcpy.da.SearchCursor(fc, fields) as cursor:
for row in cursor:
if row[0]<20000 and row[0]>Zone1:
Zone1=row[0]
elif row[0]<30000 and row[0]>Zone2:
Zone2=row[0]

#keep adding elif statements to cover the rest of the Zones
#this will print out the last number used in the piano category
print "Zone1="+str(Zone1)
print "Zone2="+str(Zone2)
break

 

 

From what I can understand the if statements only take into account the first value in the column, wich in the example shape I have is ~31000 wich makes the statements false and not change the variables.

How should I approach this?

Keep in mind I'm a complete beginner 🙂

2 Solutions

Accepted Solutions
DavidPike
MVP Frequent Contributor

I've only glanced at this but I guess you just need an extra bit of logic so that the values less than 3000 etc. don't then override those of Zone 1.

I'd say just add something like below to make sure only values in 0-2000 are evaluated, then 2000-3000 etc. 

with arcpy.da.SearchCursor(fc, fields) as cursor:
  for row in cursor:
    if row[0]<20000 and row[0]>Zone1:
      Zone1=row[0]
    elif row[0]<30000 and row[0]>=20000 and row[0]>Zone2:
      Zone2=row[0]

View solution in original post

BlakeTerhune
MVP Regular Contributor

I think @DavidPike has the solution for the basic question you asked. However, seeing that you have a Zone3 option, are you able to definitively say you will always have exactly 3 "zones" of data? If it could be variable, you could write the values to a dictionary and then handle the results however you need.

This all assumes that your naming of the zones is related to the first digit of the field values. It also assumes the range of possible values is 10000 - 99999. If it goes past that, one of the zones will get overwritten with a different range. For example, Zone1 will get overwritten with the 100k values, etc.

 

recorded_zones = {}
with arcpy.da.SearchCursor(fc, fields) as cursor:
    for row in cursor:
        current_zone_value = row[0]
        # Get first digit of value to identify the zone.
        current_zone = str(current_zone_value)
        current_zone = int(current_zone[0])

        # Compare zone values and updated if current zone value is higher.
        # Defaults recorded_zone_value to 0 if not found.
        recorded_zone_value = zones.get(current_zone, 0)
        if recorded_zone_value > current_zone_value:
            recorded_zones[current_zone] = current_zone_value

# Do something with the zone values
for zone, value in recorded_zones.items():
    print("Zone{} = {}".format(zone, value))

 

View solution in original post

11 Replies
DavidPike
MVP Frequent Contributor

I've only glanced at this but I guess you just need an extra bit of logic so that the values less than 3000 etc. don't then override those of Zone 1.

I'd say just add something like below to make sure only values in 0-2000 are evaluated, then 2000-3000 etc. 

with arcpy.da.SearchCursor(fc, fields) as cursor:
  for row in cursor:
    if row[0]<20000 and row[0]>Zone1:
      Zone1=row[0]
    elif row[0]<30000 and row[0]>=20000 and row[0]>Zone2:
      Zone2=row[0]

View solution in original post

Poncio
by
New Contributor II

Sorry for the late response didn't have time to continue this...

Anyway I tried adding the lines and only prints out 0 in every zone

0 Kudos
DavidPike
MVP Frequent Contributor

just looked, for some reason I wrote 20,000 and 30,000.  change these to 2000 and 3000 and it will work.

0 Kudos
Poncio
by
New Contributor II

Still doesn't work (and it's right to put X0000 since it's a prefix and 4 digits, I simplified a bit the digits in the data of my example but kept the right digits in the code)... But I think I found why: it prints the original value of the variable (if I put in 5 instead of 0 it prints 5), wich means that the if statement is not properly changing the variable to the value of the field. I tried to change the first part and instead of "if row[0]<20000" write  "if row[0]>20000" and it works for the first zone (the elif don't seem to work even if I put >, I think it needs to be "if" and not "elif"). I think the problem is that the values in the field are not in order compared to the FID and the first number is in zone 31 (312070 to be precise and the second is 312069), this is because of how the data is gathered and I can't chage it.  

I think how it is now, it doesn't check everything but only the first row of the field?

0 Kudos
BlakeTerhune
MVP Regular Contributor

I think @DavidPike has the solution for the basic question you asked. However, seeing that you have a Zone3 option, are you able to definitively say you will always have exactly 3 "zones" of data? If it could be variable, you could write the values to a dictionary and then handle the results however you need.

This all assumes that your naming of the zones is related to the first digit of the field values. It also assumes the range of possible values is 10000 - 99999. If it goes past that, one of the zones will get overwritten with a different range. For example, Zone1 will get overwritten with the 100k values, etc.

 

recorded_zones = {}
with arcpy.da.SearchCursor(fc, fields) as cursor:
    for row in cursor:
        current_zone_value = row[0]
        # Get first digit of value to identify the zone.
        current_zone = str(current_zone_value)
        current_zone = int(current_zone[0])

        # Compare zone values and updated if current zone value is higher.
        # Defaults recorded_zone_value to 0 if not found.
        recorded_zone_value = zones.get(current_zone, 0)
        if recorded_zone_value > current_zone_value:
            recorded_zones[current_zone] = current_zone_value

# Do something with the zone values
for zone, value in recorded_zones.items():
    print("Zone{} = {}".format(zone, value))

 

View solution in original post

Poncio
by
New Contributor II

Sorry for responding this late...

Yes it's a variable amount of zones depending on the county. Right now I'm testing with a single county that has 34 zones. I'll look into this more after making it work with the county I'm testing on.

0 Kudos
BlakeTerhune
MVP Regular Contributor

How you are dividing up 34 zones? I mentioned in my post that if you are using the first digit, you'll only get nine zones before it starts repeating (1 through 9).

0 Kudos
Poncio
by
New Contributor II

Yes Zones are divided by the first or "first and second" digit only. for example zone 2 is 2XXXX while zone 20 is 20XXXX. This is one of the main reasons I wan to automatically get the last number for each zone, since arcmap also doesn't order them correctly. For now I use select by attribute SQL:" identifika LIKE '2____' "; then open the attribute table, order from last to first and look what the last used number is.

0 Kudos
BlakeTerhune
MVP Regular Contributor

So would a rule be that if the number is over 4 digits, the remainder is taken from the beginning of the number and used as the zone? So if the number was 2361867, the zone would be 236?

0 Kudos