Select to view content in your preferred language

Moving values within FC works, but not for a List of FCs

5871
27
Jump to solution
01-21-2015 11:37 AM
GabrielBacca-Cortes
Deactivated User

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)

0 Kudos
27 Replies
JoshuaBixby
MVP Esteemed Contributor

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.

0 Kudos
XanderBakker
Esri Esteemed Contributor

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)
0 Kudos
GabrielBacca-Cortes
Deactivated User

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

0 Kudos
XanderBakker
Esri Esteemed Contributor

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?

0 Kudos
XanderBakker
Esri Esteemed Contributor

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)
0 Kudos
GabrielBacca-Cortes
Deactivated User

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

0 Kudos
XanderBakker
Esri Esteemed Contributor

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.

0 Kudos
XanderBakker
Esri Esteemed Contributor

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

GabrielBacca-Cortes
Deactivated User

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

0 Kudos
SusanJones
Frequent Contributor

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

0 Kudos