Select to view content in your preferred language

Copy Row fromr spatial Join featues

711
8
02-14-2014 07:27 AM
TonyAlmeida
Frequent Contributor
I am trying to populate some fields from the spatial join features but i am not getting it to populate.
The idea is to create a point feature and have that point feature populated with x,y and AddressID
And info from the Parcels. This would be used as tool so i don't have to manually enter the information especially when i am creating a lot of points.

The fcJoin do not have an AddressID, so i have tried to use ACCOUNT to sort because both fcJoin and fcTarget have the ACCOUNT field but nothing gets populated.

Any help would be greatly appreciated.

The code currently works but does not populate the ACCOUNT,OwnerName, SiteAddres from the parcels.

current code
fcTarget = 'TonyTwoWay.DBO.TT'   #Points
        fcJoin = 'testParcelsAdmint'    #Parcels
        fcOutput = 'Points_joined'  

        arcpy.SpatialJoin_analysis(fcTarget, fcJoin, fcOutput, 'JOIN_ONE_TO_ONE', 'KEEP_COMMON')

        curR = arcpy.SearchCursor(fcOutput, '', '', '', 'AddressID A')
        curW = arcpy.UpdateCursor(fcTarget, '', '', '', 'AddressID A')

        # init rowW and rowR
        rowW = curW.next()
        rowR = curR.next()

        while rowR:
            currentAddress = rowR.AddressID
            print 'current add: ' + currentAddress
            while rowW.AddressID != currentAddress:
                rowW = curW.next()
            if rowW.ACCOUNT == rowR.ACCOUNT_1:
                 rowW.OwnerName = rowR.OwnerName_1
                 rowW.SiteAddres = rowR.SiteAddres_1
                 # etc., etc., fill in the rest
            curW.updateRow(rowW)
            rowR = curR.next()
        # changed the delete statement, targeting the cursor objs (rather than the row objs)
        del rowW, rowR
Tags (2)
0 Kudos
8 Replies
MichaelVolz
Esteemed Contributor
Can you get a print out of what rowR.OwnerName_1 and rowR.SiteAddres_1 are being populated with?
0 Kudos
TonyAlmeida
Frequent Contributor
OwnerName will be populated with "John Doe"
rowW.SiteAddres will be populated "with 1245 Hall st"

I have attached a table after the spatial join.
and some sample data.

Thanks for your response and help!
0 Kudos
RichardFairhurst
MVP Honored Contributor
I am trying to populate some fields from the spatial join features but i am not getting it to populate.
The idea is to create a point feature and have that point feature populated with x,y and AddressID
And info from the Parcels. This would be used as tool so i don't have to manually enter the information especially when i am creating a lot of points.

The fcJoin do not have an AddressID, so i have tried to use ACCOUNT to sort because both fcJoin and fcTarget have the ACCOUNT field but nothing gets populated.

Any help would be greatly appreciated.

The code currently works but does not populate the ACCOUNT,OwnerName, SiteAddres from the parcels.

current code
fcTarget = 'TonyTwoWay.DBO.TT'   #Points
        fcJoin = 'testParcelsAdmint'    #Parcels
        fcOutput = 'Points_joined'  

        arcpy.SpatialJoin_analysis(fcTarget, fcJoin, fcOutput, 'JOIN_ONE_TO_ONE', 'KEEP_COMMON')

        curR = arcpy.SearchCursor(fcOutput, '', '', '', 'AddressID A')
        curW = arcpy.UpdateCursor(fcTarget, '', '', '', 'AddressID A')

        # init rowW and rowR
        rowW = curW.next()
        rowR = curR.next()

        while rowR:
            currentAddress = rowR.AddressID
            print 'current add: ' + currentAddress
            while rowW.AddressID != currentAddress:
                rowW = curW.next()
            if rowW.ACCOUNT == rowR.ACCOUNT_1:
                 rowW.OwnerName = rowR.OwnerName_1
                 rowW.SiteAddres = rowR.SiteAddres_1
                 # etc., etc., fill in the rest
            curW.updateRow(rowW)
            rowR = curR.next()
        # changed the delete statement, targeting the cursor objs (rather than the row objs)
        del rowW, rowR


Don't use the old cursors.  Use da. cursor only.  The speed difference is more than 10 times as fast.  Populate a list or dictionary with the read cursor once and then process the write cursor to locate the match in the list or dictionary.  That will improve speed 100 fold.  The code you have would work insanely slow with any large dataset.

You logic is wrong for embedded cursors.  But embedded cursors suck.  But to do what you want you have to reinitialize the write cursor inside the read cursor for every row read.  For every record read the entire write cursor has to be restarted and reprocessed.  Very bad for memory and speed.  If you had 1,000 read records and 1,000 write records you would have to process close to 1,000,000 cursor next statements.  That is 1,000,000 hits to your hard drive.  Insane.  Querying a list or dictionary from memory is the only way to do this and have any speed worth spit.

The inner loop condition needs to check for the current address and the addressID match in one conditional statement, not separate statements.  If a currentaddress is match but an AddressID is not no more rows will be read and nothing will be written.

As written the write cursor never reads backwards for currentaddresses that were skipped by the previous current address and once you finish going through the set of the write addresses once, you are not going to write anything else.
0 Kudos
TonyAlmeida
Frequent Contributor
Seems like this would require some one with good knowledgeable of python. I am a newbie to python.
I am not sure how dictionary would create a spatial join. If it's not to much to ask i would like to see my data in the code you are describing. if anyone could help me out i would gratefully appreciative.
0 Kudos
by Anonymous User
Not applicable
You were close....The below code worked for me.  I discarded the output fc since it didn't seem like you were using it for anything.  I added a different parameter called add fields so you can just select all the fields you want from the parcels filled in to the target points.  Try the attached toolbox.

import arcpy
arcpy.env.overwriteOutupt = True

def joinAtts(fcTarget, fcJoin,  add_fields):

    # fix args
    if type(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')
    return

if __name__ == '__main__':

    # grab args
    argv = tuple(str(arcpy.GetParameterAsText(i)) for i in range(arcpy.GetArgumentCount()))

    # Run it
    joinAtts(*argv)
    
0 Kudos
TonyAlmeida
Frequent Contributor
Caleb1987 that's pretty neat.

I would prefer this to be in a tool, because the two targets would not change nor would the fields that would be copied.
I would modify it my self but i am not to familiar on what's going on in the code. I would also like to combine it with the creating feature points from my first post.

Could you describe what is going here?
dict([(r.JOIN_FID,[r.getValue(f) for f in add_fields]) for r in curR])

How are you getting the input parameters into the script.
I see argv = tuple(str(arcpy.GetParameterAsText(i)) for i in range(arcpy.GetArgumentCount()))
but i am not sure how it's going into the code.
0 Kudos
by Anonymous User
Not applicable
Caleb1987 that's pretty neat.

I would prefer this to be in a tool, because the two targets would not change nor would the fields that would be copied.
I would modify it my self but i am not to familiar on what's going on in the code. I would also like to combine it with the creating feature points from my first post.

Could you describe what is going here?
dict([(r.JOIN_FID,[r.getValue(f) for f in add_fields]) for r in curR])

How are you getting the input parameters into the script.
I see argv = tuple(str(arcpy.GetParameterAsText(i)) for i in range(arcpy.GetArgumentCount()))
but i am not sure how it's going into the code.


Hi Tony,

I'm not sure what you mean by preferring it in a tool?  I attached a toolbox that has a script tool in for this python script.  Or do you mean as a Python add-in for ArcMap?

The line:
dict([(r.JOIN_FID,[r.getValue(f) for f in add_fields]) for r in curR])


Is creating a python dictionary.  These store key : value pairs.  In this case, I am taking the OID (TARGET_FID field) of the spatial join as the key for each row in the parcels and then the value is a list of the values of all the fields to be added back into the points ['OwnerName','ACCOUNT','SiteAddress'].  This is used later to add these values to the point based on the OID in the points being matched to the TARGET_FID field in the dictionary from the spatial join.

This part:
argv = tuple(str(arcpy.GetParameterAsText(i)) for i in range(arcpy.GetArgumentCount())) 


Is just creating a tuple of all the arguments that will be passed into the function from the script tool interface.  I like to do it that way because it keeps it dynamic and I don't have to type something like:

fcTarget = arcpy.GetParameterAsText(0)
fcJoin = arcpy.GetParameterAsText(1)
etc...

Here is a screenshot of the tool in the attached toolbox from the last post:
[ATTACH=CONFIG]31597[/ATTACH]
0 Kudos
TonyAlmeida
Frequent Contributor
yes a Python add-in for ArcMap.

I don't understand what the r in r.JOIN_FID and the r or the f in [r.getvalue (f) is?

How are you passing the arguments in the function of the script.

I have always passed them like you posted.

fcTarget = arcpy.GetParameterAsText(0)
fcJoin = arcpy.GetParameterAsText(1)
0 Kudos