2

I have two polyline layers with corresponding attributes. Each layer has 100,000+ rows. I need to calculate the distance between the corresponding features from each layer.

E.g.

Layer 1:

FID | LineID
 1     1234
 2     5678
 3     9012

Layer 2:

FID | LineID
 1     9012
 2     1234
 3     5678

I need to find the distance between the rows from each layer that match by LineID.

ESRI had a blog about using model builder to create a Near By Group tool - https://blogs.esri.com/esri/arcgis/2010/09/16/nearbygroup/

The tool seems to stall out (probably because of the large number of rows). Does anyone have any other ideas on how I can accomplish this task?

  • Do Layer 1 and Layer 2 correspond 1:1? Do you want distance from line midpoint to midpoint, an average distance from all vertices to all vertices, or what? – Andy Bradford Mar 18 '16 at 18:15
  • 1
    They do not correspond 1:1, but I can easily separate them out so that for every LineID there is a matching LineID in the other layer. Outside of that, there are attributes in each layer that don't exist in the other. Average distance estimation should be fine, but really whatever is easiest. This is just an exploratory analysis to tell us what lines we need to be looking at... I'm just trying to bin lines that are >200 ft away from their corresponding line in the other layer. – Chris Mar 18 '16 at 18:35
  • I generally get much better performance on large datasets from ArcPy, are you comfortable with a Python-based solution? – Andy Bradford Mar 18 '16 at 18:45
  • Yes. I code in Python for everything else. I just haven't started using the arcpy module yet and I was hoping I could just do this quickly instead of figuring out arcpy. Can you point me in the right direction as far as how I might want to accomplish this task with arcpy? – Chris Mar 18 '16 at 18:50
  • Save your model builder as Python and take a look at that also – Brad Nesom Mar 18 '16 at 19:46
2

One of the options is field calculator. Place 1 layer at the top of your table of content and use this on a new numeric field of second layer.

def FindD ( shp, FID ):
  mxd = arcpy.mapping.MapDocument("CURRENT")
  lr=arcpy.mapping.ListLayers(mxd)[0]
  with arcpy.da.SearchCursor(lr, 'Shape@',r'"LINEID"='+str(FID)) as cursor:
      for row in cursor: a=row[0]
  try: return a.distanceTo(shp)
  except: return -1

=========================

FindD ( !Shape!, !LIDONE! )

This is essentially the same what @Andy Bradford suggesting. You'll have to change naming of matching fields. Code assumes matching field is numeric. If not use FID instead of str(FID). Query I used in cursor is valid for shapefiles.

  • Oh, very neat! I didn't know you could access other layers in the ToC from Field Calculator. – Andy Bradford Mar 18 '16 at 20:22
  • It gives you a lot of power, e.g. gis.stackexchange.com/questions/124398/… – FelixIP Mar 18 '16 at 20:25
  • This is very cool! I didn't realize you could do that either. I'm running it right now. It looks like it could take a couple of hours even with attribute and spatial indices. At least I can see it's calculating though! I'll update after it finishes. – Chris Mar 18 '16 at 21:39
  • I didn't mention that first thing is to test it on selection, say couple hundred of records. And yes, script would digest it in less than a minute. Calculator is much slower, but ridiculously simple, because it provides immediate access to fields – FelixIP Mar 18 '16 at 22:17
  • This is great! I think you'll need to account for records that don't have a match though. Make the function return null if there isn't a matching line id. – RHB Mar 19 '16 at 2:42
0

I don't have comparable datasets that I can test this on, but I think your best bet relies on an arcpy.da.UpdateCursor cycling through whichever feature class you want to possess the distance as an attribute. For neatness it might be best to limit this to those lines that have a match in the other. For the sake of clarity I'm going to assume you want the distance attribute to end up in Layer 1.

Here's the flow inside the cursor loop:

  • Get the LineID from the current Line1 feature, and use arcpy.SelectFeatureByAttribute to select the corresponding feature in Layer 2. Use its centroid property to return a Point geometry object, and save it as a variable.

  • Use an arcpy.da.SearchCursor, nested within the UpdateCursor, to cycle through Layer 2. Cursors honor selections, so it won't search all 100K of them, just the one that was selected. ArcPy's Geometry has a distanceTo method. Use that to obtain a distance from the selected feature, and save that as a variable.

  • after the SearchCursor nested loop completes, use UpdateCursor to insert the distance into one of Layer 1's variables.

  • call UpdateCursor's updateRow(row) method on the cursor to save changes.

  • Loop ends, and cycles to the next feature in Layer 1

I realize that this is both clumsy and throwing you into the deep end of Arcpy, but it's how I would solve this kind of problem.

  • your code can be improved through use of dictionary. Create it, and iterate through 1st set populating dictionary, key=id, value=shape. Go through 2nd set with update cursor, read id, get shape from dictionary and do whatever needed with it, e.g. find distance to shape in 2nd set. Just a thought. – FelixIP Mar 19 '16 at 0:12
  • And you can also combine the first search cursor and the update cursor, as well as use a where clause on the second cursor to return just the one record you want. And if there isn't a matching line id, you'll know to return null for the distance. – RHB Mar 19 '16 at 2:54
0

It seems that there are multiple ways to do this. I have always used the Generate Near Table tool with the option to find multiple features. It is indirect. After you run the tool you have to join the appropriate attributes back and select the records where the attributes match to find your matched records. So, if the above answers don't suit you, you could try this.

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.