3

I am developing an ArcGIS Pro 3.1.0 toolbox (atbx) and one of the tools I'm creating is selecting a set of polylines (which are river centrelines) and merging them into a single long polyline. Research has pointed me to the shapely unary_union() function as an efficient method for merging the lines into a single polyline. I installed shapely using pip and can confirm that I have shapely '2.0.1' installed and when I import shapely.geos the version returned for that is '3.11.1-CAPI-1.17.1'

My input data is a UK river network with some polylines selected, so data is in a file geodatabase and the Feature Class is British National Grid, I show a small example below:

Input data

I have developed the following code to do the merge:

import shapely
import arcpy
xyresolution = 0.0001 # XY Resolution of Feature CLass

# Read selected polyline geometries into list
lp = list()
with arcpy.da.SearchCursor("Rivers","SHAPE@") as cursor:
    for row in cursor:
        geom = row[0]
        lp.append(geom)

# Convert arcpy geometry into shapely geometry
ls = list()
for geom in lp:
    ls.append(shapely.set_precision(shapely.wkb.loads(bytes(geom.WKB)), xyresolution))
    
# Union lines
aLineString = shapely.unary_union(geometries=ls)

# convert line back into arcpy geometry
newpolyline = arcpy.FromWKB(aLineString.wkb)

# Write out to temporary Feature Class
sr = arcpy.SpatialReference(27700) # BNG
with arcpy.EnvManager(outputCoordinateSystem=sr, addOutputsToMap=True):
    arcpy.CopyFeatures_management([newpolyline], r"C:\Scratch\fGDB_Scratch.gdb\fcUnionline")

My initial outputs all came out as MULTILINESTRING which is not what I wanted, I wanted a single linestring so I could convert back into an arcpy polyline. More research hinted towards it being a precision issue hence me using the shapely.set_precision() function in the above code.

But even with that addition when I check the output loaded back into ArcGIS Pro, its clearly multi-part and not in sequence.

Bad result

If I go down the route of repeating the use of the Union() method of the arcpy polyline on a set of selected river centrelines, it is slow compared to the shapely.unary_union() but the end result is a single polyline, not multipart, flowing in a source to sea direction, just what I wanted.

How do I correctly use the unary_union() function?

It seems to me that it merges the lines into a single line but keeping them as separate parts. I understood the unary_union() would combine them into a single line. For the record I have tried a range of precision values from 10 to 0.00001 and the output is exactly the same.

2
  • Had the same issue and solved with linemerge, but what's the difference with shapely.line_merge()?
    – Binx
    May 3 at 20:22
  • geopandas.dissolve() also faces a similar issue. Is there a solution for that as well?
    – Binx
    May 3 at 20:27

1 Answer 1

2

Based upon the suggestion by @user30184 I tweaked the code to use linemerge. So the only line that needed to change was

aLineString = shapely.unary_union(geometries=ls)

to

aLineString = shapely.ops.linemerge(ls)

I did have to put these import statements in to:

import shapely
import shapely.wkb
import shapely.ops

This appears to have worked although I have yet to do any performance testing with it against repeated use of union() on an arcpy polyline. It is certainly less lines of code!

I can confirm the linemerge is working as expected and is blisteringly fast! 15 minutes down to 13 seconds.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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