4

I want to perform a spatial join to find the join point (a node in the code below) that is closest to a target point (a consumer in the code below). In the result, I only need certain attributes from both input features:

  • node: "ID", "name"
  • consumer "ID", "a_value"

For doing this in arcpy it seems that I need a FieldMappings object to specify which columns I want to keep, but I can't figure out how. There are few examples in the documentation, but they appear to be more complex than what I need (merge rules an all that)

How do I perform a spatial join in arcpy where the result only contains specific columns?

fieldmappings = arcpy.FieldMappings()
fieldmap_consumer = arcpy.FieldMap()
fieldmap_node = arcpy.FieldMap()

# How to specify columns to be included in join result?    

arcpy.SpatialJoin_analysis(target_features = paramConsumerFeatures,
  join_features = paramNodeFeatures,
  out_feature_class = paramWS + "\\" + paramOutFile + "_tmpjoin",
  join_operation = "JOIN_ONE_TO_ONE",
  join_type = "KEEP_ALL",
  field_mapping = fieldmappings,
  match_option="CLOSEST",
  distance_field_name="join_dist")
  • Just remove unwanted fields – FelixIP Jun 24 '16 at 8:53
  • Can you give an example? I have no practical experience with field mappings in arcpy, so I don't even know how to create a "default" field mapping that includes all fields that I could remove fields from (the suggested approach makes sense though) – Christoph Jun 24 '16 at 8:56
  • 1
    I suggest using Python's os.path.join() for your output_feature_class path instead of concatenating with "\\". Simply import the os library, then change that line to out_feature_class = os.path.join(paramWS, paramOutFile + "_tmpjoin"). – Paulo Raposo Jun 24 '16 at 9:59
4

The above doesn't use field maps correctly; you instantiate a couple of them, but don't define anything in them. Field maps are useful when you want to consolidate/combine/concatenate/perform math on more than one input field for one output field.

If you're aim is simply to keep certain wanted fields from the set of all input fields, the following should do the trick. This is, as @FelixIP suggests, merely a matter of removing the ones you don't want, but below, we remove them from the "menu" of possible output fields before performing the merge, rather than deleting them from the saved feature classes later (which would generally be much more time-consuming, since it generally involves reading and writing to the hard disk a bunch).

Before you conduct the spatial join:

fieldmappings = arcpy.FieldMappings()

# Add all fields from inputs.
fieldmappings.addTable(paramConsumerFeatures)
fieldmappings.addTable(paramNodeFeatures)

# Name fields you want. Could get these names programmatically too.
keepers = ["want_this_field", "this_too", "and_this"] # 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))

# Then carry on...
arcpy.SpatialJoin_analysis(......)

See also the "Merge example 2 (stand-alone script)" on this page: http://pro.arcgis.com/en/pro-app/tool-reference/data-management/merge.htm

2

As @FelixIP comments I think it is easier to drop unwanted fields. Here is what your code would look like, using the fieldInfo object:

import arcpy

def filter_fields(FC, fieldList):

    # List input fields
    fields= arcpy.ListFields(FC)

    # Create a fieldinfo objects
    fieldinfo = arcpy.FieldInfo()

    # Iterate over input fields, add them to the FieldInfo and hide them if
    # they aren't in the list of fields to be kept
    for field in fields:
        if not field.name in fieldList:
            fieldinfo.addField(field.name, field.name, "HIDDEN", "")

    # Copy features to a layer using the FieldInfo
    temp = arcpy.Describe(FC).baseName + "_temp"
    arcpy.MakeFeatureLayer_management(FC, temp, "", "", fieldinfo)

filter_fields(paramConsumerFeatures, ["ID", "a_value"])
filter_fields(paramNodeFeatures, ["ID", "name"])

arcpy.SpatialJoin_analysis(target_features = arcpy.Describe(paramConsumerFeatures).baseName + "_temp",
  join_features = arcpy.Describe(paramNodeFeatures).baseName + "_temp",
  out_feature_class = out,
  join_operation = "JOIN_ONE_TO_ONE",
  join_type = "KEEP_ALL",
  match_option="CLOSEST",
  distance_field_name="join_dist")
0

What I meant is limiting spatial join by excluding field mapping, I.e. ) after keep all.

Field mapping is optional for spatial join.

Next step create list of fields of the output.

List2remove =filter(completeList not in fields2keep)

Delete field(spjoinOutput,list2remove)

I am on the phone and have to use pseudo code

0

You can build fieldmappings using arcpy.FieldMap(). Here a sample with list of target field 'list_fields_target' and list of join fields 'list_fields_join'. In this code, for demo, in join fields I also change the name of field inserting a prefix (for example you may have fields in target and join with same name)

    field_mappings = arcpy.FieldMappings()
    print 'Add fields target feature class ...'

    for field_target in list_fields_target:
        field_map = arcpy.FieldMap()
        field_map.addInputField(target_feature_class, field_target)
        field_mappings.addFieldMap(field_map)

    print 'Add fields join nella feature class...'
    for field_join in list_fields_join:
        field_map = arcpy.FieldMap()
        field_map.addInputField(join_feature_class, field_join)
        field = field_map.outputField
        field.name = 'join_' + field.name
        field.aliasName = field.name
        field_map.outputField = field
        field_mappings.addFieldMap(field_map)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.