Copy selected features to geodatabase feature class

5789
34
Jump to solution
06-11-2015 08:23 AM
CCWeedcontrol
Occasional Contributor III

I am working on creating a addon button to update some address points and copy that updated feature. The first part of the code does what it is suppose to do (only update the selected feature) but the second part of the code doesn't do what it is suppose to do and that is copy "only" the selected feature to the file geodatbase feature class. The code runs fine i don't get any errors but the second part of the codes doesn't copy the selected feature.

I would also like to an an "if" statement. if there is no feature selected i want it to do nothing or tell me there is nothing selected. if there is something selected i want it to only updates the selected feature and only copy the selected feature. Any ideas?

import arcpy, time
import pythonaddins
import os

#populate selected feature 
APT = "TEST"
arcpy.env.overwriteOutput = True
mxd = arcpy.mapping.MapDocument("CURRENT")
if int(arcpy.GetCount_management(APT).getOutput(0)) > 0:
    rows = arcpy.UpdateCursor(APT)
    for row in rows:
        row.FacltyType = ("Single Family Home")
        row.StructType = ("Primary, Private")
        row.Verified = ("Yes, GRM, TA")
        row.Status = ("Active")
        row.StructCat = ("Residential")
        row.APA_CODE = ("1110")
        rows.updateRow(row)
    del row, rows

#Copies address point to backup address points in filegeodatabase

fc1 = "CCAP"

#Database
workspace = r"C:\GIS\CCAP\CCAP.mdb"
arcpy.env.overwriteOutput = True
# Start an edit session. Must provide the worksapce.
edit = arcpy.da.Editor(workspace)

# Edit session is started without an undo/redo stack for versioned data
#  (for second argument, use False for unversioned data)
edit.startEditing(True)

# Start an edit operation
edit.startOperation()

if int(arcpy.GetCount_management(APT).getOutput(0)) > 0:
    arcpy.Append_management(APT, fc1, "NO_TEST")

# Stop the edit operation.
edit.stopOperation()

# Stop the edit session and save the changes
edit.stopEditing(True)

arcpy.RefreshActiveView()
Tags (1)
0 Kudos
34 Replies
CCWeedcontrol
Occasional Contributor III

Richard, thank you for your help, i gratefully appreciate it.

The reason i have two update cursors is because i need to update "only" the selected features (could be 1 or 20 or 100) of FC layer first with the first arcpy.da.UpdateCursor, then after the attributes have been updated i need to copy over the features that were updated in the first cursor to incidentsFC. I was trying to implement the InsertCursor you suggested and since none of the FC layers get copied over i used another updatecursor.

The FC already has the already has "Account" and "SiteStreet, those are fileds i need to copy over to the incidentFC as well .

The code you posted give me an error;

Runtime error

Traceback (most recent call last):

  File "<string>", line 26, in <module>

RuntimeError: unknown geometry token 'SHAPE@CENTROID.X'

import arcpy   
from datetime import datetime as d   
startTime = d.now()   
  
#set to folder where features are located   
arcpy.env.workspace = r"C:\GIS\CCAP\CCAP_NEW.mdb" #on windows use \ instead of /   
arcpy.env.overwriteOutput = True   
#---------------------------   
#define variables for cursor   
#---------------------------   
FC = "test"   
incidentsFC = "CCAP"   

parcelsCount = int(arcpy.GetCount_management(FC).getOutput(0))

dsc = arcpy.Describe(FC)     
     
rowInserter = arcpy.da.InsertCursor(incidentsFC, ["SHAPE@", 'Account', 'SiteStreet'])  
  
selection_set = dsc.FIDSet     
if len(selection_set) == 0:   
    print "There are no features selected"   
         
elif parcelsCount >= 1:       
    with arcpy.da.UpdateCursor(FC, ["FacltyType", "StructType", "Verified", "Status", "StructCat", "APA_CODE", "ACCOUNT", 'SiteStreet', 'SHAPE@CENTROID.X', 'SHAPE@CENTROID.Y']) as rows:   
        for row in rows:   
            row[0] = ("Single Family Home")       
            row[1] = ("Primary, Private")       
            row[2] = ("Yes, GRM, TA")       
            row[3] = ("Active")       
            row[4] = ("Residential")       
            row[5] = ("1110")  
            ACCOUNT = row[6]  
            SiteStreet = row[7]       
            X = row[8]  
            Y = row[9]  
            rows.updateRow(row)  
  
            inPoint = arcpy.PointGeometry(arcpy.Point(X,Y))   
            rowInserter.insertRow((inPoint, ACCOUNT, SiteStreet))  
del row  
del rows   
del rowInserter  
  
arcpy.RefreshActiveView()                           
try:   
    print '(Elapsed time: ' + str(d.now() - startTime)[:-3] + ')'   
  
except Exception, e:   
    # If an error occurred, print line number and error message   
    import traceback, sys   
    tb = sys.exc_info()[2]   
    print "Line %i" % tb.tb_lineno   
    print e.message  
0 Kudos
RichardFairhurst
MVP Honored Contributor

I fixed the code in my previous post.  SHAPE@X is the Centroid, so I changed SHAPE@CENTEROID.X and Y to the correct syntax.

I see nothing that indicates that you need another cursor.  My code will back up each selected point and should include any attributes of the FC pioint when the point is being inserted through the InsertRow metnod.  Note that my code gets the point and ACCOUNT and SiteStreet inserted in one command.  If there are other shared fields, just read them from the FC and follow the pattern to insert them while the point feature is being created.

You can insert the point and all attributes of the point at the same time with one insert cursor.  The only reason attributes are not being copied is that you are not including the fields in one cursor or the other, either to be read from the updateCursor or to be written to the point being inserted while it is being inserted.

Since I have no idea what your data actually looks like and I cannot divine what you really want, I just made the code do what the code you posted did. If you think your other code did something else point it out.

I assumed you never wanted a back up of points if no selection existed on your FC.  If that is not the case, let me know.  That is the only thing my code won't do.

CCWeedcontrol
Occasional Contributor III

After making the correction to the SHAPE@X AND SHAPE@Y the code ran fine. You code make more sense now that i can see it. I did not know that you can use insertRow of one layer inside an updateCursor for a different layer.


I need to copy pretty pretty much every field of the selected point or points to the back up, i was just testing my code and figured that once i got it working i could add the other fields but there are like 50 fields and i would prefer not to have to type every one. I think you touched on this with dictionaries and lists?
Yes, if nothing is selected then i don't need anything backed up.

I have attached a small portion of the feature classes.

0 Kudos
RichardFairhurst
MVP Honored Contributor

Yes, lists are the key to what you want to do.  that is why the arcpy.ListFields function returns a list of field objects (not just field names).  With two of these lists from different databases you can create a looping structure that is nearly identical to the code I provided to relate the two lists and perform updates.  The list of field objects can easily be converted to the list of field names used by the cursors.

So here is some code that should work for relating two field lists for two different data sources using the ListFields function.  Since the field lists for both the update cursor and insert cursor match you can use the same row object for the updateRow and InsertRow methods:

import arcpy     
from datetime import datetime as d     
startTime = d.now()     
     
#set to folder where features are located     
arcpy.env.workspace = r"C:\Users\OWNER\Desktop\Test" #on windows use \ instead of /     
arcpy.env.overwriteOutput = True     
#---------------------------     
#define variables for cursor     
#---------------------------     
FC = "test"     
incidentsFC = "CCAP"


FCfields = arcpy.ListFields(FC)  
incidentsFCfields = arcpy.ListFields(incidentsFC)  
# Create a field list of fields you want to manipulate and not just copy  
# All of these fields must be in the incidentsFC  
manualFields =  ["FacltyType", "StructType", "Verified", "Status", "StructCat", "APA_CODE", "ACCOUNT", 'SiteStreet', 'SHAPE@X', 'SHAPE@Y']  
matchedFields = []  
for manualField in manualFields:  
    matchedFields.append(manualField.upper())  
for FCfield in FCfields:  
    for incidentFCfield in incidentsFCfields:  
        # if FCfield.name.upper() == incidentFCfield.name.upper() and \  
        # FCfield.type == incidentFCfield.type and \  
        # incidentFCfield.editable() and \  
        # not FCfield.name.upper() in matchedFields:  
        if FCfield.name.upper() == incidentFCfield.name.upper() and FCfield.type == incidentFCfield.type and incidentFCfield.editable == True and not (FCfield.name.upper() in matchedFields):  
            matchedFields.append(FCfield.name)  
            break  
  
parcelsCount = int(arcpy.GetCount_management(FC).getOutput(0))   
  
dsc = arcpy.Describe(FC)       
  
rowInserter = arcpy.da.InsertCursor(incidentsFC, matchedFields)      
     
selection_set = dsc.FIDSet       
if len(selection_set) == 0:     
    print "There are no features selected"
           
elif parcelsCount >= 1:         
    with arcpy.da.UpdateCursor(FC, matchedFields) as rows:     
        for row in rows:     
            row[0] = ("Single Family Home")         
            row[1] = ("Primary, Private")         
            row[2] = ("Yes, GRM, TA")         
            row[3] = ("Active")         
            row[4] = ("Residential")         
            row[5] = ("1110")     
            rows.updateRow(row)     
       
            rowInserter.insertRow(row)   
    del row     
    del rows     
    del rowInserter
   
arcpy.RefreshActiveView()                           
try:   
    print '(Elapsed time: ' + str(d.now() - startTime)[:-3] + ')'   
   
except Exception, e:   
    # If an error occurred, print line number and error message   
    import traceback, sys   
    tb = sys.exc_info()[2]   
    print "Line %i" % tb.tb_lineno   
    print e.message
CCWeedcontrol
Occasional Contributor III

I am getting an error on line 17 "unexpected character after line continuation character.

I believe the forward slashes are erroring out on lines 17, 25-27. I also noticed that some fields in the manualFields list have single quotes and other have double quotes is this correct?

0 Kudos
RichardFairhurst
MVP Honored Contributor

Python doesn't care about double or single quotes, except that they are paired when they enclose a string   The slashes are just for readability and according to some posts I read were supposed to act as line continuations.  So I have just removed them and put the line break version as a comment so it can be read..

0 Kudos
CCWeedcontrol
Occasional Contributor III

I get the folloing on line 20

Runtime error

Traceback (most recent call last):

  File "<string>", line 20, in <module>

AttributeError: 'str' object has no attribute 'name'

0 Kudos
RichardFairhurst
MVP Honored Contributor

Fixed.  That was a simple copy paste error that carried over from the list of field objects and incorrectly applied to the list of field name strings.  Although I do want to make my post have the code correct, you should also not just report the error, but attempt to figure out what an error like that is telling you and attempt to fix it yourself.

Once this new code works you will need to mark it as the answer for others.

0 Kudos
CCWeedcontrol
Occasional Contributor III

Richard thank your your patience and help. python is not my strong point obviously.

i am not familiar with list. when i first got the error i removed .name from manualField.name.upper but once i removed i got an error on line 35, in TypeError: 'bool' object is not callable. i proceeding to remove all of them from line 28 and got error an line 23, in 'Field' object has no attribute 'upper'. So i didn't understand the error so that's why i posted the error i got. i am still stuck on the error.

Thanks.

0 Kudos
RichardFairhurst
MVP Honored Contributor

I believe that error occurred, because I just put "incidentFCfield.editable() and " and did not put "incidentFCfield.editable() == True and..."  Try the revised code from my post again.  The name property is not the problem and this is not a list issue, it is a field object property and expression issue.