Hi Everyone -
I have a code that moves values around within a FC [which is the result of an intersection] from one field to another so that I will have them all previously intersected values aligned in one single row. The code works well when I apply it to one FC at a time, but when I extend it to a List of FCs, it does not work. I've tried fixing it by playing with the indentation of the UpdateCursor lines, but it didn't work. Any idea what might be happening/missing ?
On another token, it seems to me that what I am trying to do, it could be done a lot simpler, any ideas on how to optimize it ?
Thanks much !
Gabriel
import arcpy, os
from arcpy import env
# Set environment settings
env.workspace = r"C:\GIS\Track1\1_Orig\int2"
# Set local variables
copyFields = ("PorousMed","K_1","Pity_1","Leng_m")
insertFd1 = ['PM1','K1','P1','leng_m1']
insertFd2 = ['PM2','K2','P2','leng_m2']
insertFd3 = ['PM3','K3','P3','leng_m3']
insertFd4 = ['PM4','K4','P4','leng_m4']
insertFd5 = ['PM5','K5','P5','leng_m5']
valueList = []
try:
fcList = arcpy.ListFeatureClasses("","POLYLINE")
for fc in fcList:
print fc
rows = arcpy.da.SearchCursor(fc, copyFields)
for row in rows:
valueList.append(row[0])
valueList.append(row[1])
valueList.append(row[2])
valueList.append(row[3])
cursor = arcpy.UpdateCursor(fc, insertFd1)
for row in cursor:
row.setValue("PM1",valueList[0])
row.setValue("K1",valueList[1])
row.setValue("poros1",valueList[2])
row.setValue("leng_m1",valueList[3])
cursor.updateRow(row)
del cursor, row
cursor = arcpy.UpdateCursor(fc, insertFd2)
for row in cursor:
row.setValue("PM2",valueList[4])
row.setValue("K2",valueList[5])
row.setValue("poros2",valueList[6])
row.setValue("leng_m2",valueList[7])
cursor.updateRow(row)
del cursor, row
cursor = arcpy.UpdateCursor(fc, insertFd3)
for row in cursor:
row.setValue("PM3",valueList[8])
row.setValue("K3",valueList[9])
row.setValue("poros3",valueList[10])
row.setValue("leng_m3",valueList[11])
cursor.updateRow(row)
del cursor, row
cursor = arcpy.UpdateCursor(fc, insertFd4)
for row in cursor:
row.setValue("PM4",valueList[12])
row.setValue("K4",valueList[13])
row.setValue("poros4",valueList[14])
row.setValue("leng_m4",valueList[15])
cursor.updateRow(row)
del cursor, row
cursor = arcpy.UpdateCursor(fc, insertFd5)
for row in cursor:
row.setValue("PM5",valueList[16])
row.setValue("K5",valueList[17])
row.setValue("poros5",valueList[18])
row.setValue("leng_m5",valueList[19])
cursor.updateRow(row)
del cursor, row
except:
print arcpy.GetMessages(0)
print arcpy.GetMessages(1)
print arcpy.GetMessages(2)
Solved! Go to Solution.
Bigger picture, you don't need to be using both search cursors and update cursors since both cursors are open on the same FC. You can iterate over an update cursor without updating any values, in effect using it like a search cursor. Usually you wouldn't want to do that because it creates more locks and may have a bit more overhead in terms of performance. In this case, since you are going to open update cursors on the FC already, just work with update cursors.
Furthermore, you should be able to restructure the code to do everything with a single update cursor. Instead of creating a new update cursor each time, since your insertFD lists aren't doing anything anyways, you can just reset the cursor and iterate over it again. Resetting a cursor and reusing it is much more efficient and clean in terms of locks than recreating new cursors every time.
Sorry Gabriel, it is still unclear what you mean exactly, but if I have to rewrite what your original code was trying to do, then it would be something like this.
import arcpy, os from arcpy import env # Set environment settings env.workspace = r"C:\GIS\Track1\1_Orig\int2" # Set local variables dct_flds = {'PorousMed': ['PM1','PM2','PM3','PM4','PM5'], 'K_1': ['K1','K2','K3','K4','K5'], 'Pity_1': ['P1','P2','P3','P4','P5'], 'Leng_m': ['leng_m1','leng_m2','leng_m3','leng_m4','leng_m5']} # create list of fields from dictionary (contains all fields: input and output) flds = [] for k, lst in dct_flds.items(): flds.append(k) for fld in lst: flds.append(fld) try: fcList = arcpy.ListFeatureClasses("","POLYLINE") for fc in fcList: print fc with arcpy.da.UpdateCursor(fc, flds) as curs: for row in rows: for fld_in, lst_out in dct_flds.items(): val_in = row[flds.index(fld_in)] for fld_out in lst_out: row[flds.index(fld_out)] = val_in curs.updateRow(row) except: print arcpy.GetMessages(0) print arcpy.GetMessages(1) print arcpy.GetMessages(2)
Thanks Xander - I ran the script you sent, but didn't run. The [flds] list looks very different from what I need. So I am hoping that by adding the fields on top here, it is clearer how the code should deliver the results I want.
PM PM1 PM2 pm5
K_1 K1 K2 k5
Pit_1 P1 P2 p5
LenM Lm1 Lm2 lm5
[ 0 1 2 3 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
4 5 6 7 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
8 9 10 11 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
12 13 14 15 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
16 17 18 19] 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
After dissolving I will be getting:
PM1 PM2 pm5
K1 K2 k5
P1 P2 p5
Lm1 Lm2 lm5
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
OK, I think I am starting to get the picture when there are 5 features. But with if the featureclass has more or less, what should happen then?
The best thing would be to share some sample data. That would make it so much easier. My next best guess is this (not testes and should best be run on a copy of the data):
import arcpy, os from arcpy import env # Set environment settings env.workspace = r"C:\GIS\Track1\1_Orig\int2" # Set local variables dct_flds = {'PorousMed': ['PM1','PM2','PM3','PM4','PM5'], 'K_1': ['K1','K2','K3','K4','K5'], 'Pity_1': ['P1','P2','P3','P4','P5'], 'Leng_m': ['leng_m1','leng_m2','leng_m3','leng_m4','leng_m5']} # create list of fields from dictionary (contains all fields: input and output) flds = [] for k, lst in dct_flds.items(): flds.append(k) for fld in lst: flds.append(fld) flds_in = dct_flds.keys() try: fcList = arcpy.ListFeatureClasses("","POLYLINE") for fc in fcList: print fc # create the list from the input fields valueList = [] with arcpy.da.SearchCursor(fc, flds_in) as curs: for row in curs: valueList.append(list(row)) with arcpy.da.UpdateCursor(fc, flds) as curs: for row in rows: for fld_in, lst_out in dct_flds.items(): # val_in = row[flds.index(fld_in)] for fld_out in lst_out: num = int(fld_out[-1:]) lst_vals = list(valueList[num]) row[flds.index(fld_out)] = lst_vals[flds_in.index(fld_in)] curs.updateRow(row) except: print arcpy.GetMessages(0) print arcpy.GetMessages(1) print arcpy.GetMessages(2)
Thanks Xander - not yet... I am attaching a sample set of 5 FCs together with a copy of my code and a copy of your code. Please bear in mind that for simplicity I had changed the names of the fields in the version of the code I've posted here in the forum.
The first FC "xy_1.shp" includes the results of running my code. Tthat's the way it should look for the rest of FCs.
I just noticed that you are in Medellin. I am from Colombia, my family lives in Cali, just came back last week actually.
Thanks again for your help on this !
Regards,
Gabriel
You're welcome, but don't thank me yet.. there are still some things that need to be resolved. I just downloaded the files (thanks) and will have a look at it to see if with the additional explanation I can make it work.
This code seems to get the result (assuming that I understand it now):
import arcpy, os import sys import traceback from arcpy import env # Set environment settings # env.workspace = r"C:\GIS\Track1\1_Orig\int2" env.workspace = r"C:\Forum\updateCursorsAtts\testdata" # Set local variables dct_flds = {'PorousMed': ['PM1','PM2','PM3','PM4','PM5'], 'Kcond_1': ['Kcond1','Kcond2','Kcond3','Kcond4','Kcond5'], 'Porosity_1': ['Poros1','Poros2','Poros3','Poros4','Poros5'], 'Leng_m': ['leng_m1','leng_m2','leng_m3','leng_m4','leng_m5']} # changed fieldnames corresponding to the data # PorousMed: Text # K_1= Kcond_1: Double # Pity_1=Porosity_1: Double # Leng_m: Double def_tuple = ("",0,0,0) # create list of fields from dictionary (contains all fields: input and output) flds = [] for k, lst in dct_flds.items(): flds.append(k) for fld in lst: flds.append(fld) flds_in = dct_flds.keys() try: fcList = arcpy.ListFeatureClasses("","POLYLINE") print fcList for fc in fcList: print fc # create the list from the input fields valueList = [] with arcpy.da.SearchCursor(fc, flds_in) as curs: for row in curs: valueList.append(list(row)) # correct for less than 5 elements while len(valueList) <= 5: valueList.append(def_tuple) with arcpy.da.UpdateCursor(fc, flds) as curs: for row in curs: for fld_in, lst_out in dct_flds.items(): # val_in = row[flds.index(fld_in)] for fld_out in lst_out: num = int(fld_out[-1:]) lst_vals = list(valueList[num]) row[flds.index(fld_out)] = lst_vals[flds_in.index(fld_in)] curs.updateRow(row) except Exception as e: print e tb = sys.exc_info()[2] tbinfo = traceback.format_tb(tb)[0] pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1]) msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n" print pymsg + "\n" print msgs
I'll attach the updated dataset for you to check the result.
Kind regards, Xander
if the feature Class has more, those values do not get transfered, if it has less, their value are empty for strings/text or zero.
I'll likely in the future increase the number from 5 to 10 just to be safe but it will not be likely to have more than 8-10. I just need something that works first...
thanks !
G
Hi
I had exactly this last week with using the arcpy.da.InsertCursor and arcpy.da.SearchCursor.
Seems that can only use one cursor at a time.
In the end I pulled all my search records into an array and used them as part of my insert/update records.
Took a bit of getting my head around, but got there in the end.
Here is my logic:
#todo: process Layer
print "\nProcess CAFS Layer"
#todo: search Data
recs = arcpy.da.SearchCursor(in_table = "EMU_VIEW", field_names = ["VehicleId", "Timestamp", "Longitude", "Latitude"])
rows = []
for rec in recs:
pt = [rec[2], rec[3]]
row = [pt, rec[1], rec[0], "CAFS", rec[1], rec[2], rec[3]]
rows.append(row)
del recs
#todo: insert Data
print "insert Data"
fldList = ["SHAPE@XY", "DateTime", "VehicleID", "FeedType", "Timestamp", "Longitude", "Latitude"]
irecs = arcpy.da.InsertCursor(in_table = fc, field_names = fldList)
for row in rows:
irecs.insertRow(row)
del irecs
Susan