Create points without XY from a table in ArcPy

I had a point feature class containing features with unique names. I also had a table containing hundreds of records, each “linking” to the point feature classes via name. Normally, I could create points for the records by using Make Query Table.

I say “linking” because from looking at the data, I could see which records belonged to which point, but unfortunately there were spelling mistakes and different naming conventions e.g. if the point was called “ABC Sewage Treatment Works”, some of its matching records in the table would be “ABC WWTP”, “AB-C Waste Water Treatment Plant”.


'''
@author Cindy Jayakumar
@date 31/01/2017
– Inserts a new point with the selected geometry in to_lyr
– Adds attributes to that point from from_lyr
– Updates the record in from_lyr
Uses selected features
For the python window in ArcMap
'''
import arcpy
from_lyr = r'C:\Some\Arb\Folder\work.gdb\tbl_test'
mxd = arcpy.mapping.MapDocument("CURRENT")
out_lyr = arcpy.mapping.ListLayers(mxd, "lyr")[0]
'''
– Select the single point in to_lyr that will have its geometry duplicated
– Select the rows in from_lyr that you want to be inserted into to_lyr
'''
def duplicateAssets(to_lyr):
# Matching point is selected in to_lyr
geom = [geo[0] for geo in arcpy.da.SearchCursor(to_lyr, "SHAPE@")][0]
# Create insert cursor on same layer
inscursor = arcpy.da.InsertCursor(to_lyr, ("SHAPE@", "Unique_ID"))
with arcpy.da.UpdateCursor(from_lyr, ("Unique_ID", "Matched")) as cursor:
for row in cursor:
# Build the new point to be inserted
point = [geom, row[0]]
inscursor.insertRow(point)
print("Inserted " +str(int(row[0])))
# Update the record with the name of the layer the point was inserted into
row[1] = to_lyr.datasetName
cursor.updateRow(row)
del inscursor
duplicatePoint(out_lyr)

Create points at set distances and split line

This week I wrote a script to create points along an existing line based on distances found in a spreadsheet, and create a new line from the original line which is the length of the last distance recorded. That was a bit of a mouthful, so I will post it here in stages. Some helpful tips were found in the ArcGIS Help (as always), as well as the always helpful ArcPy cafĂ© (here and here). In reference to that last link, creating the new line would have been much easier using 10.3’s segementAlongLine, but since that’s not in general release yet, it was the long way around for me.

'''
Created on 4 Nov 2014

@author: Cindy Williams
'''

import arcpy

# Environment settings
arcpy.env.overwriteOutput = True
arcpy.env.workspace = r"C:\Some\Arb\Folder\work.gdb"

''' Inputs
'''

ftr_baseline = "ftr_baseline" # Dissolved baseline feature class

ftr_distance = "ftr_distance" # New line feature class

ftr_points = r"ftr_points" # Created points feature class

# Table with distance data
print "Converting table..."
tbl_data = arcpy.conversion.ExcelToTable(r"C:\Some\Arb\Folder\distances.xls",
                                         r"tbl_data", 
                                         "data")

sr = arcpy.Describe(ftr_baseline).spatialReference.exporttostring() # Spatial reference

lst_points = [] # List for created points

The workflow is as follows:

  1. Working with only the geometry of the line is more efficient, so retrieve the shape of the first record in the existing line feature class. As there is only one record anyway, I’ve included two methods of doing this in the code. The one that’s not commented out is the preferred one.
  2. # Load line geometry
    # geom_line = [row[0] for row in arcpy.da.SearchCursor(ftr_baseline, "SHAPE@", "#", sr)][0]
    geom_line = arcpy.da.SearchCursor(ftr_baseline, "SHAPE@").next()[0]
    
  3. Create the point geometries by reading in the km values from the table, converting to metres, accumulating the distance and adding the the new point feature into the list. This is accomplished using an update cursor. Next, use an insert cursor to write the points to disk i.e. to the blank point feature class which has a matching schema.
    acc_dist = 0 # Accumulated distance
    
    # Create points along line according to distance
    with arcpy.da.SearchCursor(tbl_data, ["Day", "KM"], "#", sr) as cursor:
        for row in cursor:
            acc_dist += row[1]*1000 # Accumulate the distance
            pnt = geom_baseline.positionAlongLine(acc_dist) # Create point geometry
            lst_points.append((row[0], row[1], pnt)) # Add value to point list
            print "Appended {}".format(row[0]) 
    
    # Write points to disk
    ins_cursor = arcpy.da.InsertCursor(ftr_points, ["Day", "Dist_km", "SHAPE@XY"])
    for pnt in lst_points:
        ins_cursor.insertRow(pnt)
    del ins_cursor
    
  4. Finally, get the last point that was added, split the line at this point and write it to disk. I’m not sure if there is a better way to get the last entry – I did not want to retrieve it from the new point feature class as it already exists in the list.
    # Get point geometry from the tuple in the last list entry
    end_pnt = lst_points[len(lst_points) - 1][2] 
    first_line = arcpy.management.SplitLineAtPoint(geom_baseline, end_pnt, arcpy.Geometry())[0]
    arcpy.management.CopyFeatures(first_line, ftr_distance)
    
    print "Script Complete."
    

    Full script is here.