I have 2 layers, one representing streets, and one representing pipes. The pipe layer has a street field that I want it to be automatically filled (I want the pipe to show the street that it's on) I tried performing a spatial join based on 'closest' but I encountered the following problem: many pipes never intersect the center of the streets they're on (they are usually parallel), and, at the spatial join, those respective pipes don't get the needed data from the street they go along but from the ones that are perpendicular (cause they intersect the pipes, so they have one point that is closest).
[GIS] Performing spatial join between lines that travel along each other in ArcGIS Desktop
arcgis-desktopspatial-join
Related Solutions
Run the spatial join tool again, but this time use the points as the target feature. Set the match option to Intersect. Set the Join Operation to One to One.
This will join the attributes of the grid to the point that it intersects. This will give you an output feature class that contains a grid reference for each point, which is what you stated as your desired output.
This is a more efficient solution than pushing the point attributes to the grids. You will still end up with a grid reference for each point, and you can run statistics/queries to view all the points that fall in a certain grid.
You can do this using some Python code and the pandas module which is included in 10.5. All input Point feature classes need to be in one database (and no other features). They all need to have a field called grid_code
. A field will be added to each of the feature classes named gcode+feature class name, for example gcode_Point1. This is then given the value of grid_code. Then all fcs are merged together, exported to pandas, grouped by xy coordinates (which need to be exactly the same for overlapping points for it to work. But this can be adjusted by rounding the coordinates) so overlapping Points are combined and all non-overlapping Points kept. This is then exported to a new feature class.
Backup your data Before you try it! The code can be executed in the Python window after you change Point_database.
import arcpy
import pandas as pd
point_database = r'C:\Test.gdb' #All input feature classes here, nothing else. Change to match the name of your database
output_fc = 'MegaMerge'
arcpy.env.workspace = point_database
all_features = arcpy.ListFeatureClasses()
for feature in all_features:
fname = 'gcode_{0}'.format(feature)
arcpy.AddField_management(in_table=feature, field_name=fname, field_type='DOUBLE')
with arcpy.da.UpdateCursor(feature,['grid_code',fname]) as cursor:
for row in cursor:
row[1]=row[0]
cursor.updateRow(row)
arcpy.Merge_management(inputs=all_features, output='all_points')
fieldlist = [f.name for f in arcpy.ListFields('all_points') if f.name.startswith('gcode')]
df = pd.DataFrame.from_records(data=arcpy.da.SearchCursor('all_points',['SHAPE@XY']+fieldlist), columns=['SHAPE@XY']+fieldlist)
df_grouped = df.groupby('SHAPE@XY').sum()
arcpy.CreateFeatureclass_management(out_path=arcpy.env.workspace, out_name=output_fc,
geometry_type='POINT',
spatial_reference=arcpy.Describe(all_features[0]).spatialReference)
for name in list(df_grouped.columns.values):
arcpy.AddField_management(in_table=output_fc, field_name=name, field_type='DOUBLE')
icur = arcpy.da.InsertCursor(output_fc, ['SHAPE@XY']+fieldlist)
for row in df_grouped.itertuples(index=True, name=None):
icur.insertRow(row)
del icur
Best Answer
I've face a similar problem and created a programmatic tool that would:
Shorten my street centerline. Here I would take it from .4 to .6 for example (in this case I would consider only the dashes)
Street
==========
After shortening
====--====
I would buffer it for a small ammout, let's say 10% of the original street lenght. Imagine that you are buffering only the dashes in the schematic "drawing above".
Try to intersect it with pipes.
You can repeat 2 and three until you've found a certain number of pipes. The idea for shortening the center line is to eliminate the cases where you other perpendicular lines that you do not want.
Check a less ugly scheme:
Another approach is to just buffer, intersect and compare the angles. You can safely set a threshold of what "parallel" is. You will never have straight and parallel lines in this cases (some will be parallel, but that depends on digitizing). You take only the pipes that have similar angles to your centerline.