Spatial join without creating a new feature class

15440
34
03-07-2012 12:57 PM
Status: Implemented
Labels (1)
JakeKrall
Occasional Contributor III

We used to be able to do a "spatial join without creating a new feature class" in AV 3.x.  This would be a most useful tool for everyday use it seems without creating useless feature classes that you have to go back and delete.

Esri, can't you bring this tool back from the archives for ArcGIS 10.1.x???

I would really like to see it added to the Toolbox!

34 Comments
JonGreene1
 I actually found this forum as I was researching a solution.  The last post was 2012 so please forgive me for being late to the party.  First let me say that it is a love/hate relationship I have with ArcGIS.  I started back in the ArcInfo 7.2 days when you needed a PHD just to find the command line.  They have come a long way since then and I have grown to appreciate ArcGIS.  The thing is, I had to grow and change myself along the way in order to keep pace.  Otherwise, I was just slamming my head into the screen because the latest release didn't work exactly the way I wanted iot to.

I loved Arc3.x because most anyone with a book and some time could write avenue code, to me even easire than ArcPy these days. 

Having set at the desk many years as a user and eventually migrating to a software provider role, I understand the frustration from both perspectives.  As users, we need tools to work the way we need them to work.  As a provider it is difficult to continually improve the product, retain all previous functionality and meet every users expectations. 

All that said, the whole spatial join things has been eating away at me ever since ESRI retooled from MO to AO in 2000.  I now work in a very mission critical environment, DoD, E911, USMC, etc.  The fact that you have to create a new layer each time you want to bulk transfer attributes just does not cut it. 

I mean it use to be as simple as Spatial Join-[Shape} = [Shape], right?

Now you have to either accept the fact a new layer will be created or manually perform spatial selections and manually calculate values.  That's just not acceptable.

Instead of complaining about something that doesn't seem like it will change I decided to roll my sleeves up and see if I could create a solution.  I'm not a programer, nor an expert in model builder but was able to find video walkthroughs in just a few hours.  I build a model that transfers attributes from a polygon file to a point file based on spatial relation. 

Here's my solution:
  • First interate through each record in the polygon layer. 
  • Capture an attribute from a specific field upon each iteration and store it as a variable. 
  • Tie the polygon iteration to a spatial selection of the point file. 
  • Perform a field calculation for each interation,, passing the variable we captured earlier as an in-line variable too the field calculator.

I'm completely new to this forum and I don't see where I can upload the Model and FGDB.  I'll be happy to share what I have so please advise me as to a method of sharing should be be interested.  

So I challenge everyone to roll those sleeves up, make backups of your data first, create tools, break them just so you can fix them, and get creative.  Sorry not a dig towards anyone, just my very dry attempt of humor.

Attached is an image of the model.  Feel free to contact me and I'll be happy to share the test data and code as well.  

V/R
Jon
 

0EME0000000TxRi

 

 
JonGreene1
I made several modifications to the model.  It now has several variables and model parameters

You now can specify the selecting feature class, the field you want to transfer from, the feature class and field you want to transfer to, and the relationship class.  I have the selecting feature class filtered to allow only polygons but you can change that if needed. 

Here's the Model exported as a python script.  The blog page doesn't seem to allow me to post the actual model.  If anyone has an idea on how I can share the model then please let me know and I'll be happy to share. 

V/R
Jon
 
# -*- coding: utf-8 -*-
# ---------------------------------------------------------------------------
# SP AttTrans.py
# Created on: 2014-12-27 13:31:36.00000
#   (generated by ArcGIS/ModelBuilder)
# Usage: SP AttTrans <Feature_Class_used_for_Spatial_Selection> <From_Field> <To_Features> <To_Field> <Chose_Relationship> 
# Description: 
# ---------------------------------------------------------------------------

# Import arcpy module
import arcpy

# Load required toolboxes
arcpy.ImportToolbox("Model Functions")

# Script arguments
Feature_Class_used_for_Spatial_Selection = arcpy.GetParameterAsText(0)

From_Field = arcpy.GetParameterAsText(1)

To_Features = arcpy.GetParameterAsText(2)

To_Field = arcpy.GetParameterAsText(3)

Chose_Relationship = arcpy.GetParameterAsText(4)

# Local variables:
Selected_Features = To_Features
Calculated_Features = Selected_Features
Polygons_used_to_Select_other_Features = Feature_Class_used_for_Spatial_Selection
Value = Feature_Class_used_for_Spatial_Selection

# Process: Iterate Feature Selection
arcpy.IterateFeatureSelection_mb(Feature_Class_used_for_Spatial_Selection, "# #", "true")

# Process: Select Layer By Location
arcpy.SelectLayerByLocation_management(To_Features, Chose_Relationship, Polygons_used_to_Select_other_Features, "", "NEW_SELECTION")

# Process: Calculate Field
arcpy.CalculateField_management(Selected_Features, To_Field, "'%Value%'", "PYTHON", "")

 
JakeKrall

   Resurrecting the dead, again!Skull  Thank you Jon Greene for posting your work-around over 3 years ago (If you can post your toolbox with that tool would be a big help). I'm now lobbying again to resurrect this ever so "COOL" feature back into ArcGIS. (originally available at Arcview 3.x). Please vote up to get it implemented back into the next release.  For those who never got to see/use this tool, having the ability to join two feature classes based on their shape fields w/out creating new feature classes makes it ever so easy to update values in a table from features in proximity of the target features.

I would like to see Esri chime in here to get their input, why it was removed from Desktop in the 1st place and why it can't simply be added back?  It seems we continue to lose functionality at each new re-write of ArcGIS.  Why is that?

Two more that needs mentioning and brought back:  1. Find & Replace removed from Pro, go here to vote up, please; work-around is write some py code in the Calculate Field tool.  2. Select Path: from the coverage era (arc/node topology feature) - you could select 2 line segments and it would find and select all line segments in between.

Thank you and vote,

Jake

Bart-JanSchoenmakers

Nice to see this model here, I will start using it.

This functionality is essential especially for point polygon relationships. There shouldn’t be the need to create an output featureclass and then calculate the value through a relate.  The result of a spatail Join should also be the field value(s) needed from the join featureclass.

StevenGonzalez1

I came across this thread as I threw together the script below.

Not exactly what you're doing. This script works similarly to the model and script provided earlier, but uses search cursors instead. It's my understanding that this would be faster than the typical "Field Calculator" method, especially with a large number of records; however, the performance would probably be improved by using python dictionaries over search cursors.

'''
spatial join field calculator
stevenconnorg@gmail.com
'''

import arcpy, os, sys
from arcpy import env
env.overwriteOutput = True

# source feature
sourceFeature = arcpy.GetParameterAsText(0)
# source field
sourceField = arcpy.GetParameterAsText(1)
# target feature
targetFeature = arcpy.GetParameterAsText(2)
# target field
targetField = arcpy.GetParameterAsText(3)
# overlap type
overlap_type= arcpy.GetParameterAsText(4)
# search distance
searchDistance = arcpy.GetParameterAsText(5)

def unique_values(table , field):
    with arcpy.da.SearchCursor(table, [field]) as cursor:
        return sorted({str(row[0]) for row in cursor})

if overlap_type in ["WITHIN_A_DISTANCE_GEODESIC", "WITHIN_A_DISTANCE", "WITHIN_A_DISTANCE_3D", "INTERSECT", "INTERSECT_3D", "HAVE_THEIR_CENTER_IN", "CONTAINS", "WITHIN"]:
    if len(searchDistance) == 0:
        arcpy.AddError("You must supply a Search Distance value for overlap type "+ overlap_type+"! Try again")
        sys.exit(0)

sep = '.gdb'
workSpace = os.path.dirname(targetFeature)
workSpace = workSpace.split(sep, 1)[0]
arcpy.env.workspace = workSpace

oid = "OBJECTID"
tmpPntLayer = "in_memory\\tmpPoint"
targetLayer = "in_memory\\tmpTarget"
if arcpy.Exists(tmpPntLayer):
    arcpy.Delete_management(tmpPntLayer)

with arcpy.da.SearchCursor(sourceFeature, [oid,sourceField]) as cursorSearch:
    for row in cursorSearch:
        arcpy.MakeFeatureLayer_management(targetFeature, targetLayer)
        arcpy.MakeFeatureLayer_management(sourceFeature,tmpPntLayer,where_clause=oid +" = "+str(row[0]))
        arcpy.SelectLayerByLocation_management (targetLayer, overlap_type=overlap_type,select_features=tmpPntLayer,selection_type="NEW_SELECTION",search_distance=searchDistance)
        updateCount = arcpy.GetCount_management(targetLayer)

        with arcpy.da.UpdateCursor(targetLayer,targetField) as cursorUpdate:
            for row2 in cursorUpdate:
                if row[1] == None:
                    pass
                else:
                    row2[0] = row[1]
                    cursorUpdate.updateRow(row2)
                del row2
            arcpy.AddMessage(str(updateCount)+ " features in "+ targetFeature+ "'s field '"+targetField+"' updated to: "+str(row[1]))
            del cursorUpdate
    del row
del cursorSearch


arcpy.Delete_management(tmpPntLayer)
del tmpPntLayer
JakeKrall

Great to see this finally "Under Consideration" (6 years & 5 months later) !  However, the way I hear it, we'll never see it in the ArcDesktop/Map era.  I think those days are almost gone (~2020 maybe?)!!  Then "Pro", will be the new meanest dog on the block and hopefully in that time will be able to match up with today's ArcDesktop.   But, to address the models and scripts, these are good, but sometimes it just makes it really easy to view the data that's at or near that particular feature(s); not always to calculate values to another field.  Thank you all for posting and votin' up!

ChrisStarbird1

I've been able to work around this limitation in my models by using the "Extract Multi Values to Points" tool. This performs the operation on the input feature class without having to create a new data set. The down side is that you have to create a distance raster for each layer you want to compare your point layer to. In a modeling environment, creating a distance raster for each of your variables is likely the best approach anyway, as it is FAR more efficient from a processing standpoint than doing a spatial join.

MichaelVolz

If this idea is to be enabled in ESRI GIS software, would it occur in both ArcMap and Pro?

Andrus_Nicholas

Had to work around this issue today.

In this example it is a one to one relationship between the point feature classes where the target feature class has a uniquely identified field (I used OID).

First I had to create a new feature class on a spatial join between the two desired feature classes.

With the new feature class created (containing both tables) I then did a join by attribute on the OID (does not require a new feature class to be created). to the original feature class.

From there I was able to field calculate in the original feature class and then break the join.

Hope this helps someone!

Bart-JanSchoenmakers

For people using querys directly in the database I implemented this function to obtain the relation with points and the polygon they are in.

 

The function creates a new table. Careful, don't use big datasets, the process is too slow.

 

CREATE TABLE OUTPUTTABLE
AS
SELECT FC_input_point.FIELD1, FC_input_point.FIELD2, FC_POLYS.FIELD1, FC_POLYS.FIELD2 FROM FC_input_point pts, FC_POLYS polys
WHERE sde.st_contains(polys.shape, pts.shape) = 1;