cursor dictionary help please

734
8
02-26-2014 05:54 AM
TonyAlmeida
Occasional Contributor II
I need some help with arcpy.da.SearchCursor and dictionary.
I currently have the old Search.Cursor here
# init rowW and rowR
        curR = arcpy.SearchCursor(fcOutput)
        join_dict = dict([(r.JOIN_FID,[r.getValue(f) for f in add_fields]) for r in curR])
        del curR


I would like to use the new arcpy.da.SearchCursor with a dictionary.
I am trying to put it together with the following,
# init rowW and rowR
        with arcpy.da.SearchCursor(fcOutput,fields) as cursor:
            for row in cursor:
                cursor = dict([(r.JOIN_FID,[r.getValue(f) for f in arcpy.da.SearchCursor (fcTarget,add_fields)])
        del cursor


But no luck i would really appreciate some help please.
my fully code,
import arcpy
import pythonaddins
import os
import time
from arcpy import env

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

class Add_points(object):
    """Implementation for AddPoints_addin.Add_points (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor = 3 # Can set to "Line", "Circle" or "Rectangle" for interactive shape drawing and to activate the onLine/Polygon/Circle event sinks.
    def onMouseDownMap(self, x, y, button, shift):

        fc = "TonyTwoWay.DBO.TT"
        workspace = r"C:\Users\talmeida\AppData\Roaming\ESRI\Desktop10.1\ArcCatalog\Connection to dsd15_sqlexpress.sde"
        arcpy.env.overwriteOutput = True
        #arcpy.ChangeVersion_management('TonyTwoWay.DBO.TT','TRANSACTIONAL','dbo.DEFAULT', "")
        # 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()

        CC_list = []
        with arcpy.da.SearchCursor(fc, ["AddressID"]) as cursor:
            for row in cursor:
                try:
                    if "CC" in row[0]:
                        CC_list.append(int(row[0].strip("CC")))   
                except TypeError:
                    pass        
        del cursor

        t = Timer()
        with t:
             CC_list.sort()
             AddressID = CC_list[-1] + 1
             AddressID = 'CC' + str(AddressID)

             row_values = [(x, y, (x, y), AddressID)]
             cursor = arcpy.da.InsertCursor(fc, ["X_Coord", "Y_Coord", "SHAPE@XY", "ADDRESSID"])

             for row in row_values:
                 cursor.insertRow(row)
             del cursor

             # Stop the edit operation.
             edit.stopOperation()

             # Stop the edit session and save the changes
             edit.stopEditing(True)
             
        timetest = "completed in %.02f secs." % (t.interval)
        print timetest
#####################################################
        fcTarget = "TonyTwoWay.DBO.TT"
        fcJoin = "testParcelsAdmit"
        add_fields = ["ACCOUNT","SiteNum","OwnerName","SiteAddres","SiteNumSfx","SiteStreet","predir","StreetType","SubName"]

        # fix args
        if not isinstance(add_fields, list):
            # from script tool
            add_fields = add_fields.split(';')

        # do not need this scratch file
        fcOutput = r'in_memory\temp_join'
        arcpy.SpatialJoin_analysis(fcJoin, fcTarget,fcOutput, 'JOIN_ONE_TO_MANY')


        # grab oid field from points
        oid_t = arcpy.Describe(fcTarget).OIDFieldName

        fields = ["ACCOUNT","SiteNum","OwnerName","SiteAddres","SiteNumSfx","SiteStreet","predir","StreetType","SubName"]
        # init rowW and rowR
        with arcpy.da.SearchCursor(fcOutput,fields) as cursor:
            for row in cursor:
                cursor = dict([(r.JOIN_FID,[r.getValue(f) for f in arcpy.da.SearchCursor (fcTarget,add_fields)])
        del cursor

        # Now update the new target
        curW = arcpy.UpdateCursor(fcTarget)
        for row in curW:
            t_oid = row.getValue(oid_t)
            if t_oid in join_dict:
                for f in add_fields:
                    row.setValue(f, join_dict[t_oid][add_fields.index(f)])
            curW.updateRow(row)
        del row, curW
        arcpy.AddMessage('Updated all records sucussefully')
            
        pass
Tags (2)
0 Kudos
8 Replies
by Anonymous User
Not applicable
I think you would want to do something like this:

# Add JOIN_FID to first item in field list
add_fields.insert(0, 'JOIN_FID')

# Create dictionary
with arcpy.da.SearchCursor(fcOutput, add_fields) as rows:
    join_dict = {r[0]:[r for i in range(1,len(add_fields))] for r in rows}


Of course, you would want to make sure that the 'JOIN_FID' field is the first field in the list.

Edit:  After taking a look at your full code, I am thoroughly confused on what on what you are trying to do.  In your original code, you were trying to create a dictionary called "cursor", then deleting it right after it would be created.  Also, which feature class is this dictionary for? I'm assuming this is for the spatial join feature class? Is this to update the fcTarget later like in this [url=http://forums.arcgis.com/threads/102800-Copy-Row-fromr-spatial-Join-featues]thread[/url]?
0 Kudos
TonyAlmeida
Occasional Contributor II
Doesn't the  arcpy.SpatialJoin_analysis() perimiter "JOIN_ONE_TO_MANY" add the JOIN_FID Field first to the in_memory?
How do i check to see where the JOIN_FID field is?
0 Kudos
TonyAlmeida
Occasional Contributor II
The purpose of this tool is to create a point, populate the fields ADDRESSID, X,Y.
The ADDRESSID field is suppose to auto sequential from the last highest number but only numbers with that start with CC.
Then the point is suppose to auto populated with Parcels info, but on with the add_fields.
The spatial join, i believe is takes about 3-4 minutes to create the point and populate it.

This is the code that i had working but like i said takes 3-4 minutes to create the point.
import arcpy
import pythonaddins
import os
from arcpy import env

class Add_points(object):
    """Implementation for AddPoints_addin.Add_points (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor = 3 # Can set to "Line", "Circle" or "Rectangle" for interactive shape drawing and to activate the onLine/Polygon/Circle event sinks.
    def onMouseDownMap(self, x, y, button, shift):

        fc = "TonyTwoWay.DBO.TT"
        workspace = r"C:\Users\talmeida\AppData\Roaming\ESRI\Desktop10.1\ArcCatalog\Connection to dsd15_sqlexpress.sde"
        arcpy.env.overwriteOutput = True
        #arcpy.ChangeVersion_management('TonyTwoWay.DBO.TT','TRANSACTIONAL','dbo.DEFAULT', "")
        # 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()

        CC_list = []
        with arcpy.da.SearchCursor(fc, ["AddressID"]) as cursor:
            for row in cursor:
                try:
                    if "CC" in row[0]:
                        CC_list.append(int(row[0].strip("CC")))   
                except TypeError:
                    pass        
        del cursor

        CC_list.sort()
        AddressID = CC_list[-1] + 1
        AddressID = 'CC' + str(AddressID)

        row_values = [(x, y, (x, y), AddressID)]
        cursor = arcpy.da.InsertCursor(fc, ["X_Coord", "Y_Coord", "SHAPE@XY", "ADDRESSID"])

        for row in row_values:
            cursor.insertRow(row)
        del cursor

                 # Stop the edit operation.
        edit.stopOperation()

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

        arcpy.RefreshActiveView()
#####################################################
        fcTarget = "TonyTwoWay.DBO.TT"
        fcJoin = "testParcelsAdmit"
        add_fields = ["ACCOUNT","SiteNum","OwnerName","SiteAddres","SiteNumSfx","SiteStreet","predir","StreetType","SubName"]

        # fix args
        if not isinstance(add_fields, list):
            # from script tool
            add_fields = add_fields.split(';')

        # do not need this scratch file
        fcOutput = r'in_memory\temp_join'
        arcpy.SpatialJoin_analysis(fcJoin, fcTarget,fcOutput, 'JOIN_ONE_TO_MANY')


        # grab oid field from points
        oid_t = arcpy.Describe(fcTarget).OIDFieldName

        # init rowW and rowR
        curR = arcpy.SearchCursor(fcOutput)
        join_dict = dict([(r.JOIN_FID,[r.getValue(f) for f in add_fields]) for r in curR])
        del curR

        # Now update the new target
        curW = arcpy.UpdateCursor(fcTarget)
        for row in curW:
            t_oid = row.getValue(oid_t)
            if t_oid in join_dict:
                for f in add_fields:
                    row.setValue(f, join_dict[t_oid][add_fields.index(f)])
            curW.updateRow(row)
        del row, curW
        arcpy.AddMessage('Updated all records sucussefully')     
        pass


I posted asking for help to improve the tool and i was told that i was using the old style cursor.
so this is why i posted this thread to see if some one could help me .
I also thought that this was doing a spatial join on ALL the Parcels and that this was the reason it was taking 3-4 minutes. if this is the case how can i modify the tool to only do a spatial join to ONLY the newly created point.

yes it is to updated the fcTarget the thread.
0 Kudos
by Anonymous User
Not applicable
I think it would be much easier to do a select by location on the parcels layer to see what parcel is on the point you just created, and then do a search cursor on that one parcel record to grab the attributes you need (your "add fields") and use that dictionary to populate the record for the new point.
0 Kudos
TonyAlmeida
Occasional Contributor II
that sounds like what i need to do.
I am unsure on how to do the select by location of the new created point and then do a spatial join for just that parcel.

I have tried with the following but no success. I would be grateful for some help please.
import arcpy
import pythonaddins
import os
import time
from arcpy import env

class Timer:    
    def __enter__(self):
        self.start = time.clock()
        return self

    def __exit__(self, *args):
        self.end = time.clock()
        self.interval = self.end - self.start

class Add_points(object):
    """Implementation for AddPoints_addin.Add_points (Tool)"""
    def __init__(self):
        self.enabled = True
        self.cursor = 3 # Can set to "Line", "Circle" or "Rectangle" for interactive shape drawing and to activate the onLine/Polygon/Circle event sinks.
    def onMouseDownMap(self, x, y, button, shift):
        ###### Creats point and populates fields x,y & AddressID
        fcTarget = "TonyTwoWay.DBO.TT"
        workspace = r"C:\Users\talmeida\AppData\Roaming\ESRI\Desktop10.1\ArcCatalog\Connection to dsd15_sqlexpress.sde"
        arcpy.env.overwriteOutput = True
        
        #arcpy.ChangeVersion_management('TonyTwoWay.DBO.TT','TRANSACTIONAL','dbo.DEFAULT', "")
        # 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()

        CC_list = []
        with arcpy.da.SearchCursor(fcTarget, ["AddressID"]) as cursor:
            for row in cursor:
                try:
                    if "CC" in row[0]:
                        CC_list.append(int(row[0].strip("CC")))   
                except TypeError:
                    pass        
        del cursor

        t = Timer()
        with t:
             CC_list.sort()
             AddressID = CC_list[-1] + 1
             AddressID = 'CC' + str(AddressID)

             row_values = [(x, y, (x, y), AddressID)]
             cursor = arcpy.da.InsertCursor(fcTarget, ["X_Coord", "Y_Coord", "SHAPE@XY", "ADDRESSID"])

             for row in row_values:
                 cursor.insertRow(row)
             del cursor

             # Stop the edit operation.
             edit.stopOperation()

             # Stop the edit session and save the changes
             edit.stopEditing(True)
             
        timetest = "completed in %.02f secs." % (t.interval)
        print timetest
#####################################################
        Parcel = "testParcelsAdmit"       
        add_fields = ["ACCOUNT","SiteNum","OwnerName","SiteAddres","SiteNumSfx","SiteStreet","predir","StreetType","SubName"]

        Parcel_lyr = arcpy.MakeFeatureLayer_management(Parcel, "Parcel lyr")
        entries = int(arcpy.GetCount_management(fcTarget).getOutput(0))

        for i in xrange(entries):
            pt_lyr = arcpy.MakeFeatureLayer_management(fcTarget, "points_layer", "\"OBJECTID\"={}".format(str(i)))
            arcpy.SelectLayerByLocation_management(Parcel_lyr, "INTERSECT", pt_lyr, "", "NEW_SELECTION")

        # fix args
        if not isinstance(add_fields, list):
            # from script tool
            add_fields = add_fields.split(';')

        # do not need this scratch file
        fcOutput = r'in_memory\temp_join'
        arcpy.SpatialJoin_analysis(Parcel_lyr, fcTarget,fcOutput, 'JOIN_ONE_TO_MANY')


        # grab oid field from points
        oid_t = arcpy.Describe(fcTarget).OIDFieldName

        # Add JOIN_FID to first item in field list
        add_fields.insert(0, 'JOIN_FID')

        # Create dictionary
        with arcpy.da.SearchCursor(fcOutput, add_fields) as rows:
            join_dict = {r[0]:[r for i in range(1,len(add_fields))] for r in rows}

        # Now update the new target
        curW = arcpy.UpdateCursor(fcTarget)
        for row in curW:
            t_oid = row.getValue(oid_t)
            if t_oid in join_dict:
                for f in add_fields:
                    row.setValue(f, join_dict[t_oid][add_fields.index(f)])
            curW.updateRow(row)
        del row, curW
        arcpy.AddMessage('Updated all records sucussefully')
            
        pass
    

0 Kudos
MattEiben
Occasional Contributor
It looks like this line:

arcpy.SelectLayerByLocation_management(Parcel_lyr, "INTERSECT", pt_lyr, "", "NEW_SELECTION")


isn't making a selection.  Try applying a small search distance and you should get a selection.  Maybe something like this:

arcpy.SelectLayerByLocation_management(Parcel_lyr, "INTERSECT", pt_lyr, "1 meter", "NEW_SELECTION")
0 Kudos
TonyAlmeida
Occasional Contributor II
after adding a distance i still don't get anything. I don't get an error arcmap just keeps thinking.
Any other suggestions or help would be nice.
0 Kudos
TonyAlmeida
Occasional Contributor II
I tried to add the code that Caleb1987 posted to my code but i get an error.
any help would be helpful. thanks.

Runtime error 
Traceback (most recent call last):
  File "<string>", line 57, in <module>
  File "C:\Program Files (x86)\ArcGIS\Desktop10.1\arcpy\arcpy\arcobjects\arcobjects.py", line 1040, in setValue
    return convertArcObjectToPythonObject(self._arc_object.SetValue(*gp_fixargs(args)))
RuntimeError: ERROR 999999: Error executing function.


Here is the code i am working with
import arcpy
import pythonaddins
import os
import time
from arcpy import env

fcTarget = "TonyTwoWay.DBO.TT"
workspace = r"C:\Users\talmeida\AppData\Roaming\ESRI\Desktop10.1\ArcCatalog\Connection to dsd15_sqlexpress.sde"
arcpy.env.overwriteOutput = True

####Select by location on parcels with created point
Parcellyr = "testParcelsAdmit"

arcpy.MakeFeatureLayer_management(Parcellyr, "Parcel layer")
entries = int(arcpy.GetCount_management(fcTarget).getOutput(0))

for i in xrange(entries):
    arcpy.MakeFeatureLayer_management(fcTarget, "point layer", "\"OBJECTID\"={}".format(str(i)))
    arcpy.SelectLayerByLocation_management("Parcel layer", "INTERSECT", fcTarget, "", "NEW_SELECTION")
    #if arcpy.Exists(pt_lyr): arcpy.Delete_management(pt_lyr)

#### populates fields

add_fields = ["ACCOUNT","SiteNum","OwnerName","SiteAddres","SiteNumSfx","SiteStreet","predir","StreetType","SubName"]

# fix args
if not isinstance(add_fields, list):
    # from script tool
    add_fields = add_fields.split(';')

# do not need this scratch file
fcOutput = r'in_memory\temp_join'
arcpy.SpatialJoin_analysis("Parcel layer", fcTarget, fcOutput, 'JOIN_ONE_TO_MANY', 'KEEP_COMMON')

# grab oid field from points
oid_t = arcpy.Describe(fcTarget).OIDFieldName

# init rowW and rowR
#curR = arcpy.SearchCursor(fcOutput)
#join_dict = dict([(r.JOIN_FID,[r.getValue(f) for f in add_fields]) for r in curR])
#del curR

# Add JOIN_FID to first item in field list
add_fields.insert(0, 'JOIN_FID')

# Create dictionary
with arcpy.da.UpdateCursor(fcOutput, add_fields) as rows:
    join_dict = {r[0]:[r for i in range(1,len(add_fields))] for r in rows}

# Now update the new target

curW = arcpy.UpdateCursor(fcTarget)
for row in curW:
    t_oid = row.getValue(oid_t)
    if t_oid in join_dict:
        for f in add_fields:
            row.setValue(f, join_dict[t_oid][add_fields.index(f)])
    curW.updateRow(row)
del row, curW
arcpy.Delete_management(r"in_memory\temp_join")
arcpy.AddMessage('Updated all records sucussefully')    
0 Kudos