Finding distance between points in two different layers along route in ArcMap?

I need to find the distance between points in separate layers along a stream network. I have source sites for macro-invertebrates and sites where they are lacking. I need to find the distance between the source sites and the sites where they are not through the stream network.

I tried the linear referencing toolbox but the locate features along route tool can only use one layer of points and has not way to differentiate between sources and not source sites.

Any ideas?

I am using ArcMap 10.3?

• Have a look at www. Rivex.co.uk , this is a river network processing tool which does not require any extension. Jun 19, 2016 at 15:04

I know you are not asking for a Python solution, but that is the best way I know of to tackle this problem (but I'm sure there are better ways using Network Analyst). I made a very simple example and it worked for me. It does make some assumptions though:

1. Every line segment will have only 1 source and 1 sink that intersect it
2. The lines have an ID field of LONG type (can just field calculate the object ID, I called my field `"ST_ID"`)
3. You are using ArcGIS 10.2+
4. The points are snapped to the stream network

You can copy and paste the following code into the Python window, make sure you `import os` first though:

``````import os

def distanceBetweenPointsAlongLines(lines, stream_id, sources, sinks, out_table):
"""Find distance along lines between sources and sinks

This tool makes the following assumptions:
1. Every line segment will have only 1 source and 1 sink that intersect it
2. The lines have an ID field of LONG type (can just field calculate the object ID)

Required:
lines -- input lines
stream_id -- field with unique IDs (must be LONG)
sources -- source or origin points
sinks -- sink points
out_table -- full path to output table
"""

# step 1, spatial join the lines to both points1 & points2
tmp_sources = r'in_memory\tmp_sources'
tmp_sinks = r'in_memory\tmp_sinks'
arcpy.analysis.SpatialJoin(sources, lines, tmp_sources)
arcpy.analysis.SpatialJoin(sinks, lines, tmp_sinks)

# step 2, get line geometries in a dictionary
with arcpy.da.SearchCursor(lines, [stream_id, 'SHAPE@']) as rows:
ld = dict(r for r in rows)

# step 3, cycle through points and store in dictionaries
with arcpy.da.SearchCursor(tmp_sources, [stream_id, 'OID@', 'SHAPE@']) as rows:
source_d = {r[0]: r[1:] for r in rows}

with arcpy.da.SearchCursor(tmp_sinks, [stream_id, 'OID@',  'SHAPE@']) as rows:
sink_d = {r[0]: r[1:] for r in rows}

# step 4, create new table
path, name = os.path.split(out_table)
arcpy.management.CreateTable(path, name)
id_fields = ['Line_ID', 'Source_ID', 'Sink_ID']
for idf in id_fields:

# step 5, see where there are both sources in sinks in each line ID and fill out table
with arcpy.da.InsertCursor(out_table, id_fields + ['Distance']) as irows:
for line_id, source_atts in sorted(source_d.iteritems()):
if line_id in sink_d:
# we have a line that intersects points from both layers, find distance
source_id, source_geom = source_atts
sink_id, sink_geom = sink_d[line_id]
line_geom = ld[line_id]

# use segment along line to get segment in between points
seg = line_geom.segmentAlongLine(line_geom.measureOnLine(source_geom), line_geom.measureOnLine(sink_geom))
irows.insertRow([line_id, source_id, sink_id, seg.length])
return out_table
``````

And then to run it, you just make a variable for an output table and call the function:

``````out_tab = r'C:\TEMP\Test.gdb\Lengths'
distanceBetweenPointsAlongLines("streams", "ST_ID", "MacroInvertebrates", "low_pop", out_tab)
``````

In my case, the lines layer in the ArcMap TOC is called `"streams"`, my source points is called `"MacroInvertebrates"`, and the sinks are called `"low_pop"`. The second parameter is a `stream_id` field of the type `LONG`, I just created a field called `"ST_ID"` where I just field calculated the `OBJECTID` field. If you do something similar this should work.

The function will make an output table that can be used to join to whichever layer with a `Line_ID` (matching the `stream_id` param), a `Source_ID` (matching your source point's `OBJECTID`/`FID` field, a `Sink_ID` (matching your sink point's `OBJECTID`/`FID` field, and finally a `Distance` field, which reports the distance between source and sink points along the route (in units of the line features). Here is what my output and map looked like:

The linear referencing tools are probably the "by the book" way I would do this, but the answer from crmackey is probably a better solution for you. If the linear referencing toolbar allowed you to use you stream lines that tells me the feature is m-aware (routed line), but that doesn't necessarily mean the value was populated or that it was populated in the way you might expect. The simplest case here you would just merge your point files together and add a field to differentiate the types (source/not source), do a spatial join to the nearest line to get the Route ID field then run the locate along route, then use that output to create a line event. But this is assuming your sources/not sources are on the same route, which seems unlikely to me.

In my experience setting up routed networks is very efficient for particular tasks once it has been set up, but it is a lot of work on the front end.