#Script that computes the Percent forsted area from a landcover raster and #county zone data. Then finds the buffer distance required around sampling #routes, so the buffer frstd percent matches the county frstd percent. #BufferDist attribute of the route feature class are changed to reflect the #values found by the script. !! The BufferDist attribute will be changed. #Set environment and declare varibles # arcpy.env.overwriteOutput = True arcpy.env.workspace = "C:/CustomTools/DeerSurveyRoutes/rtsScratch.gdb" coPath = "C:/CustomTools/DeerSurveyRoutes/RtsAnlysVectors.gdb/County" rasPath = "C:/CustomTools/DeerSurveyRoutes/RtsAnlysRasters.gdb/WVUReclass" opnFrstdRas = arcpy.Raster("C:/CustomTools/DeerSurveyRoutes/RtsAnlysRasters.gdb/WVUReclass") rasCellSz = (opnFrstdRas.meanCellHeight + opnFrstdRas.meanCellWidth) / 2 rtsPath = "C:/CustomTools/DeerSurveyRoutes/RtsAnlysVectors.gdb/SmplRts2012Edited4CountyAnalysis" #Set environemt and create variables for County area tabulation # arcpy.CheckOutExtension("Spatial") arcpy.env.snapRaster = rasPath znFld = "CoZoneName" clsFld = "Value" outTble = "CoTbleOpenFrst" # Tabulate area of each class in raster and set up dictionary to hold values in table. # arcpy.sa.TabulateArea(coPath,znFld,opnFrstdRas,clsFld,outTble,rasCellSz) coOFDict = dict([((r.COZONENAME, f.name), r.getValue(f.name)) for f in arcpy.ListFields(outTble) for r in arcpy.SearchCursor(outTble)]) del r, f #Create dictionary of Rts Containing the CoZoneName, RouteID and BufferDist rtDict = dict([((r.RouteID, f.name), r.getValue(f.name)) for f in arcpy.ListFields(rtsPath) for r in arcpy.SearchCursor(rtsPath)]) del r, f #Loop to find buffer distance of each route that will contain the same forested percent as the county return BuffDist # buffCur = arcpy.SearchCursor(rtsPath) #row = buffCur.next() (not needed) for row in buffCur: buffDist = 402 frstPrcnt = 0 frstd = coOFDict[(row.getValue(znFld),'VALUE_2')] opn = coOFDict[(row.getValue(znFld),'VALUE_1')] nHbt = coOFDict[(row.getValue(znFld),'VALUE_0')] lpChkVal = frstd / (frstd + opn + nHbt) minLpChkVal = lpChkVal - (lpChkVal * .05) maxLpChkVal = lpChkVal + (lpChkVal * .05) x = 0 #Set up feature layer for Buffer analysis #thisRtID = row.getValue('RouteID') #arcpy.MakeFeatureLayer_management(rtsPath, "selectedLine", '"RouteID" = \'' + thisRtID + '\'') (good where clause example - do not delete) while frstPrcnt < minLpChkVal or frstPrcnt > maxLpChkVal: arcpy.Buffer_analysis(row.shape, "lineBuffer", buffDist,"FULL","ROUND","ALL") arcpy.sa.TabulateArea("lineBuffer","OBJECTID",rasPath,clsFld,"BufferOFTble",rasCellSz) rtOFDict = dict([((r.OBJECTID, f.name), r.getValue(f.name)) for f in arcpy.ListFields("BufferOFTble") for r in arcpy.SearchCursor("BufferOFTble")]) del r, f rtFrstd = rtOFDict[(1,'VALUE_2')] rtOpn = rtOFDict[(1,'VALUE_1')] rtNHbt = rtOFDict[(1,'VALUE_0')] frstPrcnt = rtFrstd / (rtFrstd + rtOpn + rtNHbt) newBuffVal = buffDist x += 1 if x == 30: rtDict[(row.getValue('RouteID'), 'BufferDist')] = 1 break buffDist = buffDist + (x * 5 * rasCellSz) rtDict[(row.getValue('RouteID'), 'BufferDist')] = newBuffVal #Create Cursor to iterate through rts and dictionary to update buffer distance. # updtCur = arcpy.UpdateCursor(rtsPath) for rows in updtCur: dist = rtDict[(rows.getValue('RouteID'), 'BufferDist')] rows.setValue('BufferDist', dist) updtCur.updateRow(rows) del rows, updtCur, row, buffCur
Solved! Go to Solution.
>>> # dictionary of only 2 keys, 'this' and 'that': >>> dict = {'this':123, 'that':456} >>> # looking up an exising key, 'this': >>> dict['this'] 123 >>> # setting up a var to use if a key doesn't exist, for example 0 (zero): >>> someDefaultVal = 0 >>> # using 'get' to retrieve the default assignment in the event of a missing key: >>> dict.get('theOther', someDefaultVal) 0 >>> # of course, using 'get' to retrieve an existing assignment returns the proper val: >>> dict.get('that', someDefaultVal) 456 >>>
What happens if you take out the following line?:
del r, f
NameError exception usually refers to a var ref that is unkown, either not properly initiated or already terminated...in your case, I think it's the way you initiated that python has already 'garbage collected' it and thus you don't need to use the 'del' command.
As for further comment on the efficiency of your script, let's just see how it runs 1st....leaving the testing to you.
Enjoy,
Wayne
#Set environment and declare varibles # import arcpy arcpy.env.overwriteOutput = True arcpy.env.workspace = "C:/CustomTools/DeerSurveyRoutes/RtsScratch.gdb" coPath = "C:/CustomTools/DeerSurveyRoutes/RtsAnlysVectors.gdb/County" rasPath = "C:/CustomTools/DeerSurveyRoutes/RtsAnlysRasters.gdb/WVUReclass" opnFrstdRas = arcpy.Raster("C:/CustomTools/DeerSurveyRoutes/RtsAnlysRasters.gdb/WVUReclass") rasCellSz = (opnFrstdRas.meanCellHeight + opnFrstdRas.meanCellWidth) / 2 rtsPath = "C:/CustomTools/DeerSurveyRoutes/RtsAnlysVectors.gdb/SmplRts2012Edited4CountyAnalysis" #Set environment and create variables for County area tabulation # arcpy.CheckOutExtension("Spatial") arcpy.env.snapRaster = rasPath znFld = "CoZoneName" clsFld = "Value" outTble = "CoTbleOpenFrst" # Tabulate area of each class in raster and set up dictionary to hold values in table. # arcpy.sa.TabulateArea(coPath,znFld,opnFrstdRas,clsFld,outTble,rasCellSz) coOFDict = dict([((coR.COZONENAME, coF.name),coR.getValue(coF.name)) for coF in arcpy.ListFields(outTble) for coR in arcpy.SearchCursor(outTble)]) del coR, coF #Create dictionary of Rts containing the CoZoneName, RouteID and BufferDist rtDict = dict([((rtR.RouteID, rtF.name),rtR.getValue(rtF.name)) for rtF in arcpy.ListFields(rtsPath) for rtR in arcpy.SearchCursor(rtsPath)]) del rtR, rtF #Loop to find buffer distance of each route that will contain the same forested percent as the county return BuffDist # buffCur = arcpy.SearchCursor(rtsPath) #row = buffCur.next() for row in buffCur: buffDist = row.getValue('Yds2Meters') frstPrcnt = 0 frstd = coOFDict[(row.getValue(znFld),'VALUE_2')] opn = coOFDict[(row.getValue(znFld),'VALUE_1')] nHbt = coOFDict[(row.getValue(znFld),'VALUE_0')] lpChkVal = frstd / (frstd + opn + nHbt) minLpChkVal = lpChkVal - (lpChkVal * .05) maxLpChkVal = lpChkVal + (lpChkVal * .05) x = 0 listFrstPrcnt = [] # Run buffer and table against initial value to set up comparison for min/max values arcpy.Buffer_analysis(row.shape, "lineBuffer", buffDist,"FULL","ROUND","ALL") arcpy.sa.TabulateArea("lineBuffer","OBJECTID",rasPath,clsFld,"BufferOFTble",rasCellSz) rtOFDict = dict([((r.OBJECTID, f.name),r.getValue(f.name)) for f in arcpy.ListFields("BufferOFTble") for r in arcpy.SearchCursor("BufferOFTble")]) del r, f rtFrstd = rtOFDict[(1,'VALUE_2')] rtOpn = rtOFDict[(1,'VALUE_1')] rtNHbt = rtOFDict[(1,'VALUE_0')] frstPrcnt = rtFrstd / (rtFrstd + rtOpn + rtNHbt) listVal = frstPrcnt listFrstPrcnt.append(listVal) newBuffVal = buffDist buffDist = 402 #Set up feature layer for Buffer analysis #thisRtID = row.getValue('RouteID') #arcpy.MakeFeatureLayer_management(rtsPath, "selectedLine", '"RouteID" = \'' + thisRtID + '\'') while frstPrcnt < minLpChkVal or frstPrcnt > maxLpChkVal: arcpy.Buffer_analysis(row.shape, "lineBuffer", buffDist,"FULL","ROUND","ALL") arcpy.sa.TabulateArea("lineBuffer","OBJECTID",rasPath,clsFld,"BufferOFTble",rasCellSz) rtOF2Dict = dict([((ofR.OBJECTID, ofF.name),ofR.getValue(ofF.name)) for ofF in arcpy.ListFields("BufferOFTble") for ofR in arcpy.SearchCursor("BufferOFTble")]) rtFrstd = rtOF2Dict[(1,'VALUE_2')] rtOpn = rtOF2Dict[(1,'VALUE_1')] rtNHbt = rtOF2Dict[(1,'VALUE_0')] frstPrcnt = rtFrstd / (rtFrstd + rtOpn + rtNHbt) listVal = frstPrcnt listFrstPrcnt.append(listVal) newBuffVal = buffDist x += 1 buffDist = 402 + (x * 5 * rasCellSz) if min(listFrstPrcnt) < minLpChkVal and max(listFrstPrcnt) > maxLpChkVal: break rtDict[(row.getValue('RouteID'), 'BufferDist')] = newBuffVal print row.getValue('RouteID') #Create Cursor to iterate through rts and dictionary to update buffer distance. # updtCur = arcpy.UpdateCursor(rtsPath) for rows in updtCur: dist = rtDict[(rows.getValue('RouteID'), 'BufferDist')] rows.setValue('BufferDist', dist) updtCur.updateRow(rows) del rows, updtCur, row, buffCur, ofR, ofF
>>> # dictionary of only 2 keys, 'this' and 'that': >>> dict = {'this':123, 'that':456} >>> # looking up an exising key, 'this': >>> dict['this'] 123 >>> # setting up a var to use if a key doesn't exist, for example 0 (zero): >>> someDefaultVal = 0 >>> # using 'get' to retrieve the default assignment in the event of a missing key: >>> dict.get('theOther', someDefaultVal) 0 >>> # of course, using 'get' to retrieve an existing assignment returns the proper val: >>> dict.get('that', someDefaultVal) 456 >>>
So now you have a KEYERROR, meaning you're having problems accessing the requested key (the key doesn't exist).
This is the error printed:
rtNHbt = rtOFDict[(1,'VALUE_0')]
KeyError: (1, 'VALUE_0')
The key is of course (1, 'VALUE_0') and apparently for this case it does not exist. Maybe this will help you:
https://wiki.python.org/moin/KeyError
You can think what could possibly cause this missing key and correct it or otherwise trap the error, or if you like have a default value returned.
Enjoy,
Wayne
So as a very brief example using a default value of 0 (zero):>>> # dictionary of only 2 keys, 'this' and 'that': >>> dict = {'this':123, 'that':456} >>> # looking up an exising key, 'this': >>> dict['this'] 123 >>> # setting up a var to use if a key doesn't exist, for example 0 (zero): >>> someDefaultVal = 0 >>> # using 'get' to retrieve the default assignment in the event of a missing key: >>> dict.get('theOther', someDefaultVal) 0 >>> # of course, using 'get' to retrieve an existing assignment returns the proper val: >>> dict.get('that', someDefaultVal) 456 >>>
Notice I am not saying this is the best way to handle this - the best way is to identify and handle the error...this is only illustrating an option to 'bypass' the error and return 0. You'd have to be careful that the other vals in your divisor are not zero or you'll introduce a new error, division by zero.