Multi batch spatial joins

2730
14
06-30-2021 03:35 PM
2Quiker
Occasional Contributor II

I have over 20 layers that I need to spatially join, doing separate arcpy.SpatialJoin_analysis for each one would be time consuming.  fc1 is the layer I want to multi batch the other layers in the database to.

I have tried the following but it only spatially joins the first layer in the database. Is it possible to do a multi batch spatial joins? I am going about it the wrong way?

 

 

import arcpy, os  
from arcpy import env
from datetime import datetime as d
startTime = d.now()

arcpy.env.workspace = r"C:\Temp\Default2.gdb"  
fc1 = r"C:\Temp\Default2.gdb\Parcels"

arcpy.env.overwriteOutput = True
fcs = arcpy.ListFeatureClasses() #gets the feature classes
for fc in fcs:
    print(fc)
    arcpy.SpatialJoin_analysis(fc1,fc, "SP_Test", "JOIN_ONE_TO_ONE", "KEEP_ALL", "", "INTERSECT", "", "")
print ('(Elapsed time: ' + str(d.now() - startTime)[:-3] + ')')

 

fc1 

0 Kudos
14 Replies
BlakeTerhune
MVP Regular Contributor

Is your goal to have one feature class with everything smashed into it (as many spatial joins) or to have separate feature classes, each spatial joined to only Parcels?

0 Kudos
2Quiker
Occasional Contributor II

To have one feature class with certain fields and rename some fields. I can keep certain fields with the following but I need to change some fields names and just the whole fieldmappings gives me a headache.

 

fieldmappings = arcpy.FieldMappings()

    # Add all fields from inputs.
    fieldmappings.addTable(fc1)
    fieldmappings.addTable(fc)

    # Name fields you want. Could get these names programmatically too.
    keepers = ["Field1", "Field2", "Field3", "Field4","Field5", "Field6"] # etc.

    # Remove all output fields you don't want.
    for field in fieldmappings.fields:
        if field.name not in keepers:
            fieldmappings.removeFieldMap(fieldmappings.findFieldMapIndex(field.name))

 

 

I need to be able to rename  "Field1", "Field2", "Field3", "Field4","Field5", "Field6" to something else, "AFieldA", "BFieldB", "CFieldC", "DFieldD","EFieldE", "FFieldF". No specifically these names but to something else. I also need to use a merge rule and join delimiter to one layer in the database.

0 Kudos
by Anonymous User
Not applicable

Here is the code that handles the spatial joining process:

def fieldmapping(targetFc, joinFc, keepFields):
    """
    Support function create a field map between two featureclasses
    """
    fldMap = arcpy.FieldMappings()
    # Creating field maps for the two files
    fldMap.addTable(targetFc)
    fldMap.addTable(joinFc)

    # Adds the fields from the targetFC to the list of fields that you want to keep
    keepFields.extend(i.name for i in arcpy.ListFields(targetFc))

    # Removing unwanted fields
    for field in fldMap.fields:
        if field.name not in keepFields or field.name in ['TARGET_FID', 'Join_Count']:
            fldMap.removeFieldMap(fldMap.findFieldMapIndex(field.name))

    return fldMap
        
# ----------------- 
def joinsubdivision():
    # List of fields that you want to keep from the input featureclass 
    subd = ['sub_code', 'blk_tr_no', 'lot_no', 'sub_name', 'plat_year', 'plat_month']
    # helper function to map the target featureclass to the input featureclasses fields that you want to keep.
    subdMap = fieldmapping(updatedAddress, subdivision, subd)
    lyrInMem = arcpy.SpatialJoin_analysis(inLayer, subdivision, os.path.join(in_memory, 'subdiv'), 'JOIN_ONE_TO_ONE', 'KEEP_ALL', subdMap, 'INTERSECT')
     # If needed, alter field names (alternative to having to create a specific field map for the field)
    altfields(lyrInMem, [('blk_tr_no', 'blk_tr')])

 

Hope this gives you an idea to get started and if you have any questions please feel free to ask.

 

0 Kudos
2Quiker
Occasional Contributor II

Where are you defining 'altfields', 'updateAddress' and 'subdivisions'?

0 Kudos
by Anonymous User
Not applicable

Yes, that could help.

altfields is a helper method that takes a list of tuples and runs them through arcpy.AlterField_management() to rename them:

def altfields(inLayer, flds):
    """
    Support function to alter fields
    """
    for f in flds:
        arcpy.AlterField_management(inLayer, f[0], f[1], f[1])

its use is something like:

altfields(yourlayer, [('DMSLat', 'latitude'), ('panel', 'firm_panel')])

 

'updateAddress' is the target featureclass that you want to join the other featureclasses to.

'subdivision' is the feature class that you want to join to the target featureclass.

Both of these are just variables pointing to featureclasses, which you'll change to match yours.

I see ESRI's example has changed and has improved some over the one tree example, but there is a lot of additional things happening in the example that is distracting from being able to clearly see how to make a field map.

If you want to rename the fields in the fieldmapping, you can do so by doing this:

fldMap = arcpy.FieldMappings()
... # map like fields and exclude fields you dont want 

#-----------------------
# create specific mapped fields:
specificfldmap = arcpy.FieldMap() # create FieldMap object

# add the target featureclass and its field name that you want to map.
specificfldmap.addInputField(targetfc, 'targetfcfldname') 

# add the joining featureclass and its field name that you want to map.
specificfldmap.addInputField(joinfc, 'joinfcfldname') 

# get the outputfield object
specfldobj = specificfldmap.outputField 

# set the desired outputfield name
specfldobj.name = 'newoutputfieldname'

# replace the outputfield object with the modifed version
specificfldmap.outputField = specfldmapobj 

# add your fieldmap to your fieldMappings object
fldMap.addFieldMap(specificfldmap)

# proceed with using the fldMap

 

You can iterate over a list of tuples for this part if you know the fieldnames and what you want to be mapped to in the target featureclass.

0 Kudos