select by location and calculate field from update cursor row: help

4715
4
11-05-2011 10:06 AM
RichardThurau
Occasional Contributor
Hi,
I'm trying to use update.cursor to do a spatial selection of another layer, then populate the selection layer with an attribute from the cursor layer. More specifically, I'm trying to select "parcLyr" by each feature in "JurLyr", then populate "parcLyr" field "Dist" with the value in "JurLyr" field "Jur_Name".

arcpy.MakeFeatureLayer_management(Jurs_dis, "JurLyr")
rows = arcpy.SearchCursor("JurLyr", "", "", "Jur_Name", "")
arcpy.MakeFeatureLayer_management(parcels, "parcLyr")
for row in rows:
    arcpy.SelectLayerByLocation_management("parcLyr", "HAVE_THEIR_CENTER_IN", "JurLyr", "", "NEW_SELECTION")
    arcpy.CalculateField_management("parcLyr", "Dist", "%s") %(row.Jur_Name)



I'm getting an "invalid character" error. I feel like I'm close.

Any help would be greatly appreciated.

Thanks!

Rich
Tags (2)
0 Kudos
4 Replies
KimOllivier
Occasional Contributor III
When you have a geoprocessing tool inside a cursor that loops for every feature you will have performance problems. That is because geoprocessing tools are designed to work most efficiently on a whole featureclass, not an individual feature. It should be a red flag, don't do it.

The idea of ArcGIS is that it is geo-relational, for the same reason that SQL queries are 'non procedural'. You can't specify the processing for each tuple in table join so please think of a similar expression for GIS processing as well, instead of "reinventing GIS" in the scripting language.

Either recast the problem to process the whole featureclass in one step or use a Python structure to index the attributes, such as a dictionary, which can hold many values in a list for each row.

There are several alternative approaches that spring to my mind:

    Use an arcpy.management. MakeQueryTable tool that allows a full SQL expression between tables with a one to many relation.
    Run an arcpy.analysis.SummaryStatistics Tool (not Frequency which requires an ArcInfo licence) with a case field.
    Run an arcpy.SearchCursor() once on a table to collect the counts and place in a python dictionary.
    Then run an arcpy.UpdateCursor() once to populate the other table. Note that splitting the two cursors avoids multiplying the number of searches required. If you had 1 million records in each you would then have a billion slow cursor accesses.
0 Kudos
RichardThurau
Occasional Contributor
kimo
Thanks for the reply.
I'm not having any performance issues, which, once I get this type of script to run, perhaps i will. At that point, I would submit a thread to fix.


Your other suggestions sound interesting, but a little beyond me. I'm trying to learn all I can, but at the same time not get fired for spending too much time learning and not enough doing.

If I am "identifying" parcels that are within a spatial domain of another selected layer, it seems redundant to create a 'dictionary' of this relationship anywhere except in the parcels attribute table. This is a very simple process to do in ArcMap, but as i said, trying to learn.

Thanks to another suggestion, I am able to get the code to run using the following:

arcpy.MakeFeatureLayer_management(Jurs_dis, "JurLyr")
rows = arcpy.SearchCursor("JurLyr", "", "", "Jur_Name", "")
arcpy.MakeFeatureLayer_management(parcels, "parcLyr")
for row in rows:
    arcpy.SelectLayerByLocation_management("parcLyr", "HAVE_THEIR_CENTER_IN", "JurLyr", "", "NEW_SELECTION")
    arcpy.CalculateField_management("parcLyr", "Dist_amec", '"%s" %(row.Jur_Name)', "PYTHON")


However, this code populates all the parcels with the first jurName in the JurLyr. Instead of just populating the correct parcels within each jurName. Since there is one feature for each jurName, i assumed the updatecursor would loop through the attribute table. But, maybe I need something to make this iterate?

Thanks for any input you can provide.

Rich
0 Kudos
KimOllivier
Occasional Contributor III
Forget any idea of iterating over each row. Better analysis tools do that for you.

Why not just use an overlay tool between the two featureclasses?
If you want to find if a parcel centroid is inside some other polygon featureclass then create a point featureclass of parcel centroids and use Identity_analysis.

Performance in my terms means finishing in preferably 30 seconds for something so simple, so you can run it several times until you get it right before morning tea. 😉

import arcpy
import datetime
start = datetime.datetime.now()
arcpy.env.overwriteOutput = True
arcpy.env.workspace = "e:/crs/customer/waiheke/mobile.gdb"
arcpy.FeatureToPoint_management("parcel", "in_memory/parcel_center","INSIDE")
arcpy.management.MakeFeatureLayer("E:/data/census2006/census2006.gdb/nztm/mb2006","jurs_lay","TA06V2 = '007'")
arcpy.Identity_analysis("in_memory/parcel_center", "jurs_lay", "in_memory/parcel_jurs")
# join back district to parcels
arcpy.JoinField_management("parcel", "objectid", "in_memory/parcel_jurs", "ORIG_FID", ["MB06"])
print "Done",datetime.datetime.now() - start, " seconds"

# >>> Done 0:00:26.953 seconds
0 Kudos
JenniferHorsman
New Contributor
Thank you Kim for your first suggestion! I have a similar task and was trying to write a script, but when I read your suggestion, I gave my task some more thought and realized I could do what I needed using various selections, Spatial Join, and Join by Attributes with no need for a script except to put it altogether in one place. Whew!
0 Kudos