Copy attributes from updated Table to Feature Class based on Unique ID

821
4
05-02-2017 06:40 AM
JudsonCrouch
New Contributor

Hello All,

I am working on a script to copy attributes to their respective feature from a user edited DBF to a feature class. My organization creates sites in GIS, fills in a few key attributes, exports the attribute table to a DBF where our non-GIS users update the table in excel and then export to a tab delimited text file. Previously we have taken the updated DBF table, created a join, and manually used field calculator to copy the information back into the feature class but this takes quite a bit of time when we are dealing with 30-40 fields. 

I have written a basic script so far using search and update cursors using a value dictionary to relate the SiteID field (unique value) in the DBF to the SiteID field in the feature class however I can't get past how to make the script iterate through all of the rows and update the information. 

import os
import arcpy as ap

fc = r"Path\To\SitesFc"
dbf = r"Path\To\UpdatedTable.txt"

fcfieldList = [f.name for f in ap.ListFields(fc)]
dbffieldList = [f.name for f in ap.ListFields(dbf)]

valueDict = {r[0]:(r[1:]) for r in ap.da.SearchCursor(dbf, dbffieldList)}
            #[0] is SiteID field in DBF


with ap.da.UpdateCursor(fc, fcfieldList) as updateRows:
     for updateRow in updateRows:
          siteIDVal = updateRow[2] #[2] is SiteID field in FC
          if siteIDVal in valueDict:
                 # This is where I am lost. Not sure how to iterate through the fields

               
                    updateRows.updateRow(updateRow)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I would type out updateRow = valueDict[SiteIDVal] but sometimes our field schemas change depending on the project and I want this to be a somewhat generic tool we can utilize.

Thaks in advance for the help!

Judson

0 Kudos
4 Replies
NeilAyres
MVP Alum

Row 10, the valuedict. Do you know that the first column in the variables from ListFields is actually the key value?

Have you printed and looked at what dbffieldList contains.

Line 15, I would call the item updateRow as this is the same name as the method on the cursor.

So, SiteIDVal is a Key pointer into the valueDict.

You would have to recover those values from the dict[keyval].

In what order they are in would depend on exactly what dbffieldList.

If dbffieldlist looks like :

["KeyVal", "Val1", "Val2", "Val3"]

Then index 0, becomes the Key in the dict and the value is a list starting with "Val1". Remember this when recovering the values after

if siteIDval in valueDict:

Like :

vals = valueDict[siteIDval]
v1 = vals[0] # note that "Val1" from the dbf is now the first value in the list
v2 = vals[1]
v3 = vals[2]
# then go on and construct a data list for the updateRow

Hope this helps.

JudsonCrouch
New Contributor

Neil,

Thanks for the reply. 

The keyval  SiteID is indeed the first column in dbffieldList. This all makes sense to me however I guess what I am asking is how to skip constructing a data list so that the script can be run on a table with fewer or more fields than this specific example I am working with. 

Is there a way to iterate through the fields saying:

for updateRow in updateRows:
    updateRow[x] = valueDict[SiteID][y]

This might be a simple question but my head is swimming since I haven't used dictionaries or cursors much! 

0 Kudos
NeilAyres
MVP Alum

You might do something like this, but you would have to be careful that the order in the fieldList is correct.

vals = valueDict[SiteID]
outData = []
for i, fld in enumerate(fields):
    outData.append(vals)
0 Kudos
LarryAdgate
Occasional Contributor

Hi Judson, your thread was very interesting because I am trying to do the same thing. Did you ever finalize your script and how is it working? If possible, can you forward a final copy to me

Thanks,

Larry Adgate

0 Kudos