Select to view content in your preferred language

How do I populate an attribute field with the number of selected records?

3926
39
Jump to solution
09-23-2013 08:07 AM
TysonBarlow
Occasional Contributor
I'm working with two datasets:
1) School Boundaries (polygons)
2) Students (points)


In the school boundary dataset I have fields for each grade (Grade1, Grade2, etc...) and would like to populate those fields with the number of students for each respective grade in each school boundary. The Students dataset has a field that contains each student's grade.

I have been doing it manually, but figure there should be a way to automate this process. Any help is appreciated, and if I haven't explained myself well enough, please let me know.

Thanks!
Tags (2)
0 Kudos
39 Replies
TysonBarlow
Occasional Contributor
Part of the dataset that is sensitive is the student's location. I think you're right, though. I'll edit all sensitive info and attach it to my next post.
0 Kudos
TysonBarlow
Occasional Contributor
The datasets are attached

Thanks for your help!
0 Kudos
T__WayneWhitley
Honored Contributor
Hello Tyson,
I am attaching a shp zip of some spatial join output, which I believe is the direction you are headed - it is still 'raw' output based on what you said you wanted because it is not a summary (count of the respective grades per polygon).  I just want you to at least look at the added output field (this was from the spatial join process).  Make sure it is the expected output from the join process you were looking for.....this is just a way you could start this processing utilizing the Spatial Join tool.  Further processing will be required, and can be done in addition to this although I'd probably just use a Python script.  Still I suppose this exercise was to first understand the spatial relationship between your Student points and be able to use this to 'stamp' the Elementary Boundary polygons.

The 'trick' to this execution of the Spatial Join tool (in the Analysis toolbox) was to field map the Grades txt values (the input field) to a newly defined output field using a one-to-one join operation.  Oh, and I used a comma (,) as a 'join delimiter'.

I'll see if I have time to 'finish' the results with an updatecursor processing on this intermediate output that:
1- takes the output field, splits out the txt vals and counts the unique values.
2- updates the fields you intended to populate by mapping the Grade fields with the appropriate counts.

Enjoy,
Wayne
0 Kudos
T__WayneWhitley
Honored Contributor
Something I realized that I didn't mention before - you have the option (although not really efficient) to use the option for performing a 'JOIN_ONE_TO_MANY' type of join in the spatial join operation, points to polygons (polygons are the target).  I used the 'JOIN_ONE_TO_ONE' option and used the field val 'aggregation' as the help calls it with a field map merge rule.

The difference is you'd get multiple polygon records for every Grade value from every intersecting point feature, so you can see how this is inefficient.  However, if you go this route and map the single point text value to an output field, you can then execute Frequency processing by polygons and this grade value, which will output a table with counts.  From there (if this is the simpler approach for you) I would use a nested Python sorted cursor to then loop through and transfer your count values to your designated original school polygon shapefile.

I can show you how to do that shortly - let me know if you understand what's going on so far.

Enjoy,
Wayne
0 Kudos
TysonBarlow
Occasional Contributor
This is so helpful! I am following you to this point, which is great. Just to make sure I was getting it, I followed your instructions and came up with the same intermediate output that you have using the first method you provided. Because I've got that step down pat, I would like to just continue processing from that point. Now that we have a polygon feature class with the outGrades field, I would love to go on to, as you put it...

I'll see if I have time to 'finish' the results with an updatecursor processing on this intermediate output that:
1- takes the output field, splits out the txt vals and counts the unique values.
2- updates the fields you intended to populate by mapping the Grade fields with the appropriate counts.

If you have time to do this, I would praise your name forever!

Thanks!
0 Kudos
T__WayneWhitley
Honored Contributor
Hello Tyson, sorry for the delay - more than 1 way to do this but I flung this together in IDLE, based on the last shapefile - see the attached for an 'updated' copy of the last so if you haven't changed yours, may as well overwrite it with this one.

Here's the code I used - again, since this is a 'one-off', I was just winging it with this below, so better check the shp results, the fields you designated for counts--
>>> import arcpy
>>> shp = r'E:\schoolTestData\schoolJoinToPolys4.shp'
 
>>> query = arcpy.AddFieldDelimiters(shp, 'outGrades') + ' NOT IN (\' \')'
>>> print query
"outGrades" NOT IN (' ')
 
>>> rows = arcpy.UpdateCursor(shp, query)
>>> for row in rows:
               outGrades = row.outGrades.split(',')
               outGrades.sort()
               count = 0
               compareVal = outGrades[0]
               for each in outGrades:
                              if each == compareVal:
                                             count += 1
                              else:
                                             if not compareVal in ['KA', 'KP', 'PA', 'PP']:
                                                            fieldName = 'Grade_' + str(int(compareVal))
                                             else:
                                                            fieldName = 'Grade_K'
                                                            count += row.getValue(fieldName)
                                             row.setValue(fieldName, count)
                                             rows.updateRow(row)
                                             count = 1
                                             compareVal = each
               # load the last unique val
               if not compareVal in ['KA', 'KP', 'PA', 'PP']:
                              fieldName = 'Grade_' + str(int(compareVal))
               else:
                              fieldName = 'Grade_K'
                              count += row.getValue(fieldName)
               row.setValue(fieldName, count)
               rows.updateRow(row)
 
               
>>> del row, rows
>>>  


I wasn't sure about the codes in the list ['KA', 'KP', 'PA', 'PP'], so I flung a cumulative count into K1 or whatever you called the 1st field.  Sorry if that's not quite what you intended, but easily modified.

Seriously though, the biggest hangup I had was remembering to only treat the records with values - kept getting this error:
Traceback (most recent call last):
  File "<pyshell#81>", line 21, in <module>
    fieldName = 'Grade_' + str(int(compareVal))
ValueError: invalid literal for int() with base 10: ''


And all that means is that I encountered an 'untreated' blank value, typical of shapefiles, just I was trying to filter it out using IS NOT NULL.  I ended up forming the query finally, and avoided the error with NOT IN (\' \')' which is translated as NOT IN ' '.  Details!


Enjoy,
Wayne


EDIT- think I forgot the attachment...it's there now.
0 Kudos
TysonBarlow
Occasional Contributor
So do I just open the Python window and run this code there?

I attempted that, and after changing the .shp path on line 2 to the path of the .shp on my computer, I get an error that tells me that there is "no documentation found for 'outgrades' on line 6.
0 Kudos
T__WayneWhitley
Honored Contributor
Hi Tyson and happy Friday!

I guess you need the working script file so you can apply it to your other dataset - I forgot this was just a sample.
Also, since this wasn't the Python forum, I wasn't sure how applicable it would be to post that and only posted the scripting I used (which I did interactively in IDLE, rather than commit to a script file) because frankly I don't think (and I could very well be wrong) it can be done quite the same if at all using the system ArcMap tools.  There may be luck with the Merge tool, but I still doubt it and it was just easier for me to script it.

My apologies I treated this as a 'one-off' - again, forgot all about the fact you need a little reusability.  Easy enough to modify though so that's the good news.  Did you see the attachment?  That's the file it should work on and my reasonable assumption with your error is that you named the output field in your shp something different OR you tried to load the interactive scripting as a script file and it tripped on the line I printed for checking the interpretation of the query [which correctly printed "outGrades" NOT IN (' ')].

If you would check the attached shp from my last post and make sure your previously made count fields are correctly updated...
If so, we'll go from there, changing the scripting to a script file you can simply run, is that what you want?

Enjoy,
Wayne
0 Kudos
T__WayneWhitley
Honored Contributor
okay...some quick changes, didn't test the attached script file but try running it after you:

1- import arcpy
2- set the 'shp' variable to the path of your shapefile

Off the top of my head I think that's all you need, do this in the ArcMap Python window, then load the provided script file - if this works, great (I don't usually run it this way but think it'll work!).  Of course, if you're using a shp I already edited, that won't work - it'll only add to the current counts, so use one like the orig with all zeros (0).

Hope that's the ticket...

Enjoy,
Wayne
0 Kudos
TysonBarlow
Occasional Contributor
Happy Friday to you as well!

I checked the shapefile you attached, and it does have the correct information in the grade fields, except for the grade K. This is my fault, though, because I do not have a grade field for P (preschoolers, PP, PA, P). You did assume correctly that the Grade_K field should include students with the KA or KP or K grade assignment. Grade_P could/should be another field, and should be distinguished from the Grade_K. I'm really not interested in getting the sum of preschoolers, so I wouldn't mind if they are left out of the whole thing altogether

No need to apologize, I could have been more clear on my intended use. I do plan on reusing this quite often, as district administrators often want to know how many students of each grade are in a school boundary area. With students moving in and out of the district often, this will be very helpful for me on multiple occasions in the future. I should be the one apologizing!

Changing the scripting to a file I can simply run is exactly what i'm looking for. That way I can build it into a custom tool (I think) and run it whenever I want to update the different grade fields in my boundaries feature class.

Thanks SO much!!
0 Kudos