I have an app that searches for a particular species from a point file
Once found it creates graphics for the point locations and grid polygons that encompass those points.
What I want to do now is symbolize those polygons based on how many points are found within them. I am not sure how to approach this. I think I would have to read through each polygon and determine how many points are in there and set the symbology?
So the result would be a graphics layer of polygons of varying color based on how many points are within them
Anyone have any ideas?
Solved! Go to Solution.
First off THANK YOU ALL FOR YOUR THOUGHTS AND COMMENTS
They really helped steer me in the path and direction I took...
OK this is what I did and its working....
I used the If Then to change the TYPE value in the Data to a value that would work as a field name...so I can update the Polygon Layer as some of the TYPE values were really long
import arcpy
arcpy.env.workspace = r"E:/xxxxx/xxxx/Projects/xxx/xxx.sde"
Points = r"E:/xxxxx/xxxx/Projects/xxx/xxx.sde/Locations"
Grids = r"E:/xxxxx/xxxx/Projects/xxx/xxx.sde/Grids"
print "Started"
bList = []
expression = ""
expressionValue = ""
type= ""
rowCount = 0
uniquetypeList = []
countList = []
txt_list = ""
# COUNT NUMBER OF RECORDS FOR EACH TYPE
def getFieldName(type):
if type == "Needs Repair":
return "NeedsRepair"
elif type == "Broken":
return "Broken"
elif type == "Needs Replacement":
return "NeedsReplacement"
elif type == "Schedule Fix":
return "ScheduleFix"
else:
return "nothing"
def processTypeUpdate(expressionValue, typeValues, fieldName):
expressionValue2 = expressionValue
typeName = typeValues
fieldUpdateName = fieldName
rowCount = 0
arcpy.Delete_management('in_memory/PointsInPolys')
arcpy.Delete_management('in_memory/SS_PointsInPolys')
arcpy.Delete_management('points_lyr')
arcpy.Delete_management('points_lyr2')
arcpy.MakeFeatureLayer_management(r'E:/xxxxx/xxxx/Projects/xxx/xxx.sde/Locations_Test', 'points_lyr')
results = arcpy.SelectLayerByAttribute_management ('points_lyr', 'NEW_SELECTION', expressionValue2)
arcpy.MakeFeatureLayer_management(results, 'points_lyr2')
polygonID = "ID" ## unique polygon field name
countField = fieldUpdateName # The field name in the Grids FC to update
expression = "recalc(!FREQUENCY!)"
codeblock = """def recalc(freq):
if freq > -1:
return freq
else:
return 0"""
arcpy.SpatialJoin_analysis('points_lyr2', Grids, "in_memory/PointsInPolys")
### case field returns count per unique UID
arcpy.Statistics_analysis ("in_memory/PointsInPolys", "in_memory/SS_PointsInPolys", [[polygonID, "Count"]], polygonID)
arcpy.JoinField_management(Grids, polygonID, "in_memory/SS_PointsInPolys", polygonID, "FREQUENCY")
arcpy.CalculateField_management(Grids, countField, expression, "PYTHON", codeblock)
arcpy.DeleteField_management(Grids, "FREQUENCY")
# GET THE CODES FROM THE RESULTS OF THE SELECTION
rows = arcpy.SearchCursor('points_lyr2',"","","type_name")
for row in rows:
rowCount = rowCount + 1
typeVal = str(row.type_name)
countList.append(typeVal)
txt_list = ','.join(countList)
print "number of " + typeVal + " : " + str(rowCount)
arcpy.Delete_management('in_memory/PointsInPolys')
arcpy.Delete_management('in_memory/SS_PointsInPolys')
arcpy.Delete_management('points_lyr')
arcpy.Delete_management('points_lyr2')
# TAKE TYPE NAME AND GET THE CORRECT FIELD NAME
def processtypeNames(expressionValue, typeValues):
type= str(typeValues)
expressionValue2 = "type_name = '{}'".format(type)
# GET THE CORRECT FIELD NAME
fieldName = getFieldName(type)
if fieldName == "nothing":
print "No Value"
else:
# Call the function to actually update the Field Values
uniques2 = processtypeUpdate(expressionValue2, type, fieldName)
print "corrected field name is: " + fieldName
def uniquetypeList(uniquetypeValues):
typeList = uniquetypeValues
#print typeList
for type in typeList:
#print type
expressionValue = "type_name = '{}'".format(type)
uniques = processtypeNames(expressionValue, type)
# GET UNIQUE TYPS FROM FC CREATE LIST
for feature in arcpy.ListFeatureClasses():
#print feature
with arcpy.da.SearchCursor(Points,"type_name", sql_clause=(None,'ORDER BY type_name ASC')) as SCur:
for row in SCur:
if not row[0] in bList: # if not in list then add to list
bList.append(row[0])
type = row[0]
del SCur
uniquetype = uniquetypeList(bList)
I recently did a video on this type of thing.
Here is a codepen to look at
https://codepen.io/odoe/pen/vYxYxXm
In your case, since it's just counts, it's fairly straight forward, but could be an intensive task.
const query = {
returnGeometry: true,
};
const cityResults = await cityLayerView.queryFeatures(query);
const frsResults = await frsLayerView.queryFeatures(query);
const features = [];
let temp = [...frsResults.features];
let temp2 = [];
// the loop is where you could block UI.
// You loop over polygons, then each polygon
// loops over each point to check if it's contained.
// You can mitigate this by removing found points from
// array of points with Array.splice()
for (let feat of cityResults.features) {
const graphic = feat.clone();
graphic.attributes.count = 0;
temp2 = [...temp];
for (let i = 0; i < temp2.length; i++) {
const x = temp[i];
if (
x &&
graphic.geometry &&
x.geometry &&
graphic.geometry.contains(x.geometry)
) {
graphic.attributes.count++;
temp.splice(i, 1);
}
}
features.push(graphic);
}
I added a comment in there about the performance hit you can take and one way to mitigate it. If it's a lot of points, you might need to run this iteration in a worker.
Thanks a bunch and you aint kidding that this is a heavy lift. Shifting gears a bit....wondering if I can do this via python or something. Run a script against the dataset....
Polygon Dataset with multiple fields for individual species
Run a script and have it count the number of point occurrences (species specific) in each polygon for Species A and write the number in the corresponding field. Then do this for every species. Then I have a polygon FC that I can symbolize by a given field. This should do what I want and not have to do it on the fly.
Do you know of any examples to accomplish this via python or geoprocessing tools?
I found this but I need something that I can run and let it go through everything....this is far to manual...
Why not just count the number of results (points) you get when querying the specific species before you create the polygon? Then you can add it as an attribute on the polygon graphic when you create it and symbolize with that.
I found this for python and I think it will work but I have to loop through each time with a different species name. The example just calculates the total number of points...
https://gis.stackexchange.com/questions/289273/counting-points-within-polygon-with-arcpy
CAN I DO THIS?
I can create a list of all the unique Species Names
Then Step through each Species Name and set a definition query on the Points Layer
Use this DEFINITION query result and then get the counts and update a field with the count
Then move on to the next Species Name etc etc
I should have asked this to start, but if you are using Online or Enterprise, you can use the Summarize Within analysis tool in the MapViewer Classic to do this. It will do counts and stats for you.
But you're on the right track, pre-processing is definitely the way to go if you can. I am not strong with Python though, I can fake it when I need to.
If using Python, I would use Dissolve. You can specify a Statistics Field with count, to count the number of dissolved points for each species (by name or id or whatever key field you have). Note that
If theInput Featuresgeometry type is either point or multipoint andCreate multipart featuresis checked (MULTI_PARTin Python), the output will be a multipoint feature class. Otherwise, ifCreate multipart featuresis unchecked (SINGLE_PARTin Python), the output will be a point feature class.
So this would give you a new output feature class with a count field you can symbolize on.
I am trying this....
This should loop through for each species and get me a count.
ANY thoughts to why I am getting this error?
ERROR :
Traceback (most recent call last):
File "E:\ArcGIS_Server_aws\Python_Scripts\CountBBASpecies\CountSpeciesinPolygon.py", line 61, in <module>
uniques = unique_values(expressionValue, species)
File "E:\ArcGIS_Server_aws\Python_Scripts\CountBBASpecies\CountSpeciesinPolygon.py", line 47, in unique_values
for row in cursor:
RuntimeError: Underlying DBMS error [[Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Incorrect syntax near 'Vireo'.] [BBA2.DBO.JaysTest_BirdLocations_Test]
>>>
CODE:
# COUNT NUMBER OF RECORDS FOR EACH SPECIES
def unique_values(table, field):
expressionValue = table
species = field
with arcpy.da.SearchCursor(Points, "common_name", where_clause=expressionValue) as cursor:
for row in cursor:
print row[0]
# GET UNIQUE SPECIES FROM FEATURE CLASS
for feature in arcpy.ListFeatureClasses():
with arcpy.da.SearchCursor(Points,"common_name", sql_clause=(None,'ORDER BY common_name DESC')) as SCur:
for row in SCur:
if not row[0] in bList: # if not in list then add to list
bList.append(row[0])
species = row[0]
expressionValue = "common_name = " + species
# PASS species name to Function to Count
uniques = unique_values(expressionValue, species)
your expressionValue needs to put quotes around the species to be a valid SQL statement
expressionValue = "common_name = '{}'".format(species)