So I've been using Notebooks in ArcOnline to do some batch assignments for a Workforce project. Quick run down of the project: Fire Dept needs to do bi annually inspections on every business in the city. I've built a survey in survey123 that'll handle all the questions. They'll use Workforce to dispatch their people to the locations. This is decided by fire station areas. I'd like to automate creating these assignments by the station area polygons so we dont have to do it by hand twice a year.
I have their dispatch polygons hosted on arconline but can't seem to get the script to work. Here's what it looks like, it's 100% modelled off the template on github:
conda install -c esri/label/prerelease -c esri arcgis==1.8.3 conda update -n base -c defaults conda from datetime import datetime from arcgis.gis import GIS from arcgis.geometry import Geometry from arcgis.mapping import WebMap from arcgis.apps import workforce from datetime import datetime gis = GIS("home") item = gis.content.get("afca01f6dda742e69896412da860b924") project = workforce.Project(item) # Get Layer of City Districts fireInspectionDistricts_layer = gis.content.get("0afccc9e48c3471f8bfc1954f4602c23").layers[0] fireInspectionDistricts_map = gis.map("Thornton, CO", zoomlevel=10) fireInspectionDistricts_map.add_layer(fireInspectionDistricts_layer) fireInspectionDistricts_map # Add Assignments to the Map fireInspectionDistricts_map.add_layer(project.assignments_layer) # Create a spatially enabled dataframe of the districts fireInspectionDistricts_df = fireInspectionDistricts_layer.query(as_df=True) print (fireInspectionDistricts_df) # OBJECTID ZONE UNIT STATION SHAPE_Length SHAPE_Area \ #0 1 6 None None 169552.086294 4.020346e+08 #1 2 2 None None 64910.441381 7.760154e+07 #2 3 1 None None 49842.642184 8.343908e+07 #3 4 3 None None 143750.130571 2.249331e+08 #4 5 4 None None 57284.309928 1.412634e+08 #5 6 5 None None 129542.914257 3.418221e+08 # Get all of the unassigned assignments assignments = project.assignments.search("status=0") # Assign Assignments Based on Which District They Intersect¶ tyler = project.workers.get(user_id="Tyler.Dunn@XXXXXX") brandi = project.workers.get(user_id="Brandi.Rank@XXXXXXX") for assignment in assignments: contains = fireInspectionDistricts_df["SHAPE"].geom.contains(Geometry(assignment.geometry)) print (contains) #0 False #1 False #2 False #3 False #4 False #5 False #Name: contains, dtype: bool containers = fireInspectionDistricts_df[contains] print (containers) #Empty DataFrame #Columns: [OBJECTID, ZONE, UNIT, STATION, SHAPE_Length, SHAPE_Area, SHAPE] #Index: [] if not containers.empty: fireInspectionDistrict = containers['ZONE'].iloc[0] if fireInspectionDistrict == 4: assignment.worker = tyler assignment.status = "assigned" assignment.assigned_date = datetime.utcnow() elif fireInspectionDistrict == 2: assignment.worker = brandi assignment.status = "assigned" assignment.assigned_date = datetime.utcnow() assignments = project.assignments.batch_update(assignments) # Verify Assignments are Assigned webmap = gis.map("Thornton, CO", zoomlevel=11) webmap.add_layer(project.assignments_layer) webmap
One of my concerns is that the results of containers is returning and empty dataframe and empty index.
Not sure if that's part of the issue, but at this point I've hit a brick wall.
Any suggestions?
Hi Tyler,
So it appears that the issue is with the contains operation. It is returning False which is then causing the dataframe to select nothing (resulting in an empty dataframe). A couple things you could try:
1. Check the spatial reference of the fire inspection districts layer. If it's not web-mercator, then you may need to explicitly set out_sr=102100 in the query on line 28. The workforce layer is also using web-mercator.
2. Try running the same notebook outside the AGOL hosted notebook environment (e.g. on your own local machine).
Alright so the out_sr worked, this is now what's printed for contains:
0 False 1 False 2 False 3 False 4 False 5 True Name: contains, dtype: bool
and printed for containers:
SHAPE 5 {"rings": [[[-11677745.002824906, 4853496.4840... OBJECTID ZONE UNIT STATION SHAPE_Length SHAPE_Area \ 5 6 5 None None 129542.914257 3.418221e+08
Now it's not committing the information to the assignments. When I look at the workforce project or the map that's called in the script, nothing has been updated. Any guesses?
It should always be updating the assignments. I'm guessing it's something with the if/else not working for your zones. Can you print out the fireInspectionDistrict?
#tyler = project.workers.get(name="Tyler Dunn")
tyler = project.workers.get(user_id="Tyler.Dunn@thorntonco.gov_cityofthornton")
brandi = project.workers.get(user_id="Brandi.Rank@thorntonco.gov_cityofthornton")
#print (tyler)
#print (brandi)
for assignment in assignments:
contains = fireInspectionDistricts_df["SHAPE"].geom.contains(Geometry(assignment.geometry))
#print (assignment.geometry)
#print (contains)
#0 False
#1 False
#2 False
#3 False
#4 False
#5 True
#Name: contains, dtype: bool
#print (assignments)
#print (fireInspectionDistricts_df)
containers = fireInspectionDistricts_df[contains]
#print (containers)
#OBJECTID ZONE UNIT STATION SHAPE_Length SHAPE_Area \
#5 6 5 None None 129542.914257 3.418221e+08
#print (fireInspectionDistricts_df)
if not containers.empty:
fireInspectionDistrict = containers["ZONE"].iloc[0]
print (fireInspectionDistrict)
if fireInspectionDistrict == 4:
assignment.worker = tyler
assignment.status = "assigned"
assignment.assigned_date = datetime.utcnow()
elif fireInspectionDistrict == 2:
assignment.worker = brandi
assignment.update.status = "assigned"
assignment.assigned_date = datetime.utcnow()
assignments = project.assignments.batch_update(assignments)
Prints a bunch like this:
5 5 5 5 5 5 5 5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
Okay, yeah so you need to change line 28 and 32 to use 5 and 1 in order for those assignments to be assigned to tyler and brandi. Currently, it's not assigning it to anyone.
So it ended up being that the ZONE field is a String data type. I created another field ZONE_INT as an integer and it worked.
Thanks for all the help