Is there a way to merge two point value datasets which overlap, with an argument to always take either the lowest or highest Z value at points which overlap? I want to create a hybrid dataset of two overlapping layers, with the argument to select the greatest value for Z where they overlap.

I understand that Cell Statistics can be used for this, but that requires raster inputs and outputs, I need the data to remain in an XYZ point dataset format so that it can then be exported to another software package that does not handle rasters.

I can merge the two point datasets into a shapefile using the Merge function, however this has no option to add an argument for overlapping sections.

  • 1
    Could you just confirm that points are located in exactly the same location, means exactly the same coordinates - as per definition, point doesn't have any dimension so hard to say they overlap. You may think about creating small buffer around each of them (only if their coordinates are different). And use 'dissolve' with 'statistics_fields' (your Z value) set to MIN/MAX... Have you tried that? – ChrisL Dec 15 '16 at 10:33

You might try this workflow:

arcpy.AddGeometryAttributes_management("merged", "POINT_X_Y_Z_M")


enter image description here

arcpy.Sort_management("merged", "D:/Scratch/sorted.shp", "POINT_Z ASCENDING")
arcpy.AddField_management("sorted", "XY","TEXT", field_length="50")
arcpy.CalculateField_management("sorted", "XY", expression="FormatNumber( [POINT_X],3)&FormatNumber( [POINT_Y],3)", expression_type="VB")
arcpy.DeleteIdentical_management("sorted", “XY")


enter image description here

|improve this answer|||||

Below is some python code that you can run in the python command line window in ArcMap, it will select the points with the lowest z value.

import arcpy
fl = "xxx" # This is a featureLayer in your map, you need to change this
fields = ["OID@","SHAPE@X","SHAPE@Y","z"] # Assumes you have a field called z that holds the z value
myDict = {}
with arcpy.da.SearchCursor(fl,fields) as cursor:
    for row in cursor:
        # Get row information and build XY value
        oid = row[0]
        X = str(row[1])
        Y = str(row[2])
        Z = row[3]
        XY = X + "_" + Y
        if myDict.has_key(XY):
            # XY exists now choose the minimum
            myTup = myDict[XY]
            if Z < myTup[1]:
                newTup = (oid,Z)
                myDict[XY] = newTup

            # First time for XY so insert Z
            myDict[XY] = (oid,Z)

# Now construct SQL
vals = myDict.values()
myList = []
for myTup in vals:
    oid = myTup[0]
sQuery = "OID IN " + str(tuple(myList)) # You may need to change OID to FID if you are using a shapefile

# Select the points
|improve this answer|||||
  • 1
    +1 I see str(tuple(...)) works for you. However tolerance is missing. Also I remember seeing a limit on length in SQL IN statement. Possible solution deleteRow, it wan't work on shapefile. The safest is populate another field with 0,1 – FelixIP Dec 15 '16 at 23:40
  • @FelixIP - Good point about limit on length of SQL statement and your approach of creating a flag field is certainly more scaleable. But as the original poster gives no indication on the volume of data, I'm going to leave the code example as is. – Hornbydd Dec 16 '16 at 14: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.