Trying to write a python scrip to find and dissolve pseudo nodes for a large dataset.

Anyone have any code to perform such a task?

For example, I have a road line with several end/start nodes (pseudo nodes) created by the cartographers.

Easy enough to run a topology but I have upwards of 4,000,000 +/- pseudo node to get rid of.

Software: ArcGIS 10.2.2 Python 2.7

  • Not in network? – FelixIP Feb 11 '15 at 2:34
  • 1
    Hi Jeff, welcome to GIS.SE. Can you please indicate what GIS software you're writing the script for; a brief description of what you believe a 'pseudo node' to be would also be great as ideas on this point can differ. – Michael Stimson Feb 11 '15 at 2:34
  • 1
    I have some code that might help but in my case a true pseudo node is an endpoint connecting to only one other line and sharing the same (important) attributes, but it's written in Arc 9.3 or earlier. Have you got any code so far to share? – Michael Stimson Feb 11 '15 at 2:46
  • Yes - same concept (Psuedo Node) or a node connecting only two edges with similar (same) attributes – Jeff Feb 11 '15 at 2:51
  • 1
    Is this question about just finding (flagging/displaying) pseudo nodes or their automatic removal? Either way I think the inclusion of a graphic will help nail down what is being asked. Have you reviewed the Online Help on Checking for unnecessary pseudo nodes which seems to require a Data Reviewer license? If so, then what prevents you using that as a solution would be useful to include in your question. – PolyGeo Feb 11 '15 at 2:54

The simplest way is to use FeatureVerticesToPoints to create an end points feature class, dissolve with your key fields to a temporary feature class, create end points from that then compare the original points to the dissolved end points using Near, any that don't match between the original and dissolved end points are worth looking at.

Of course in a 3 (or more) way intersection the dissolve tool will dissolve the line with the matching attributes regardless of connection which makes this method unsuitable except as a very rough guide. To get around this I created a script (in 9.3) that I've quickly converted to v10.1 to take advantage of the new cursor objects:

import os, sys, arcpy

InLayer = sys.argv[1]
MatchFields = sys.argv[2]

SearchTol = "1 Meter" # How far between endpoints before they're considered to be the same
fRange = range(len(MatchFields))

desc = arcpy.Describe(InLayer)
OIDfieldName = desc.OIDFieldName
# check it's a polyline feature class
if desc.shapeType != "Polyline":
    arcpy.AddError("This script only works on lines")

SR = desc.spatialReference
# check that the units are suitable
if SR.linearUnitName != "Meter":
    arcpy.AddError("This tool only works in projected coordinates")

Scratch = os.environ.get("TEMP") # Windows TEMP directory
Points = os.path.join(Scratch,"POINTS.shp")
Buffers = os.path.join(Scratch,"BUFFERS.shp")
BuffEx  = os.path.join(Scratch,"EXPLODED_BUFFERS.shp")
JPoints = os.path.join(Scratch,"JOINED_POINTS.shp")
SumTab  = os.path.join(Scratch,"SUMMARY_TABLE.dbf")

# clean up
if arcpy.Exists(Points):
if arcpy.Exists(Buffers):
if arcpy.Exists(BuffEx):
if arcpy.Exists(JPoints):
if arcpy.Exists(SumTab):

# you can use Make Events but the coordinates need to match
# exactly... instead I use a buffer and count.
# count the points for each polygon

# go through all the count=2 rows
with arcpy.da.SearchCursor(SumTab,"EndID","COUNT_Poin = 2") as SumCur:
    for SumRow in SumCur:
        SelectIDs = list() # start with an empty list
        with arcpy.da.SearchCursor(JPoints,"ORIG_FID","EndID = " + str(SumRow[0])) as JCur:
            for JRow in JCur:
                SelectIDs.append(JRow[0]) # add this ID to the list

        MatchValues = list()
        FirstFeature = True
        AllFieldsMatch = True

        # get the matching lines using the ORIG_FID field added by the
        # feature verticestopoints tool
        with arcpy.da.SearchCursor(InLayer,MatchFields,OIDfieldName + " in  (" + str(SelectIDs[0]) + "," + str(SelectIDs[0]) + ")") as LCur:
            # read the first features values into memory
            # then compare against the second feature
            for LRow in LCur:
                if FirstFeature:
                    FirstFeature = False
                    # put all the values into a list
                    for fIdx in fRange:
                    for fIdx in fRange:
                        if MatchValues[fIdx] != str(LRow[fIdx]):
                            AllFieldsMatch = False # if one fails they all fail
                            break                  # no point checking any more
        if AllFieldsMatch:
            # then it's a true pseudo node, insert something here

This script uses Feature Vertices to Points which requires an advanced license, if you don't have access to this there are other ways to make points from line end points in python which you can search and replace - I think this script is already too long.

  • Thanks I'll take a look. I did figure out not to verify the topology first but rather use the Topology tool "Validate Topology in a Specified Area" and I was able to remove upwards of 14,000 pseudo notes in ~ 1 hour. – Jeff Feb 11 '15 at 22:53

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.