Wednesday, 29 April 2015

arcpy - Creating a value-counting table with search- and update cursor


I'm a python beginner.


I`m working with ArcGIS 10.2.2 and IDLE Python 2.7.5



I have a shapefile with around 20 fields, each attribute has a value between -3 and 3.


This would look like this:


enter image description here


I need to count the number of occurrences of each value for every object. For this I created a new shapefile with fields where the values get counted:


enter image description here


The actual counting is my problem. My approach is to browse with search and update cursor through the files. My script does work, however there are two problems:


1.It is really slow (for a shapefile with 300 rows the program ran over 9 minutes). I tried using the arcpy.da.searchcursor but I couldn't bring it to work. 2. The way I built the script seems a little odd. I tried a lot to make it easier, but I cannot really figure out which way to go. I believe there is an easier way to do it.


try:
#getting the field names and creating a search cursor
fieldnames = arcpy.ListFields("Eignung")

srows=arcpy.SearchCursor("Eignung",fieldnames[2:18])


print "operating"
#creating a while loop to work row by row
srow = srows.next()
while srow:
# for every field in the row I get the Value
for fieldname in fieldnames[0:18]:
TheFieldName=fieldname.name

TheValue=srow.getValue(TheFieldName)

#if the Value is 0 I add "1" to the "zerofield" in the counting table
if TheValue == 0:
obj_id = srow.getValue("OBJECTID")
urowquery = '"OBJECTID" ='+ str(obj_id)
urows = arcpy.UpdateCursor("Eignung_1",urowquery)
for urow in urows:
urow.setValue("Null_",urow.getValue("Null_")+1)
urows.updateRow(urow)

obj_id +=1
del urow, urows
print "check0"
# and do the same thing for 1 and 2 and 3 and so on
elif TheValue == 1:
obj_id = srow.getValue("OBJECTID")
urowquery = '"OBJECTID" ='+ str(obj_id)
urows = arcpy.UpdateCursor("Eignung_1",urowquery)
for urow in urows:
urow.setValue("Eins",urow.getValue("Eins")+1)

urows.updateRow(urow)
obj_id +=1
del urow, urows
print "check1"
elif TheValue == 2:
obj_id = srow.getValue("OBJECTID")
urowquery = '"OBJECTID" ='+ str(obj_id)
urows = arcpy.UpdateCursor("Eignung_1",urowquery)
for urow in urows:
urow.setValue("Zwei",urow.getValue("Zwei")+1)

urows.updateRow(urow)
obj_id +=1
del urow, urows
print "check2"

elif TheValue == 3:
obj_id = srow.getValue("OBJECTID")
urowquery = '"OBJECTID" ='+ str(obj_id)
urows = arcpy.UpdateCursor("Eignung_1",urowquery)
for urow in urows:

urow.setValue("Drei",urow.getValue("Drei")+1)
urows.updateRow(urow)
obj_id +=1
del urow, urows
print "check3"

elif TheValue == -1:
obj_id = srow.getValue("OBJECTID")
urowquery = '"OBJECTID" ='+ str(obj_id)
urows = arcpy.UpdateCursor("Eignung_1",urowquery)

for urow in urows:
urow.setValue("Eins_minus",urow.getValue("Eins_minus")+1)
urows.updateRow(urow)
obj_id +=1
del urow, urows
print "check-1"

elif TheValue == -2:
obj_id = srow.getValue("OBJECTID")
urowquery = '"OBJECTID" ='+ str(obj_id)

urows = arcpy.UpdateCursor("Eignung_1",urowquery)
for urow in urows:
urow.setValue("Zwei_minus",urow.getValue("Zwei_minus")+1)
urows.updateRow(urow)
obj_id +=1
del urow, urows
print "check-2"

elif TheValue == -3:
obj_id = srow.getValue("OBJECTID")

urowquery = '"OBJECTID" ='+ str(obj_id)
urows = arcpy.UpdateCursor("Eignung_1",urowquery)
for urow in urows:
urow.setValue("Drei_minus",urow.getValue("Drei_minus")+1)
urows.updateRow(urow)
obj_id +=1
del urow, urows
print "check-3"

srow = srows.next()

print done

As I said, it does work, but it doesn't work well.



Answer



I would re-engineer your code to use the da search and update cursors as these are significantly faster. Have a look at the help file and practise, it will be worth it in the long run.


A performance improving step is to search in a single sweep through the data, collating all your numbers then write this out into a single update step. Currently you are calling multiple updates on every step through the search cursor. This would be killing your performance.


So how do you keep a count whilst stepping through with a search cursor? Well I would suggest using dictionaries. These are in-memory data structures which are very fast to read/write from.


Another off the top of my head approach is to run the summary tool grouping by objectID and field and doing a count, then repeat for every field then do a big join and export, the sort of thing you can knock together in model builder but I would imagine python approach is quicker?


No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...