ArcGIS Pro Shapely – Using shapely unary_union() Function to Union Polylines in ArcGIS Pro

arcpydissolveshapely

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.

Best Answer

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.

Related Question