Python script to create a point WITH attributes values

14061
5
06-06-2013 11:44 PM
by Anonymous User
Not applicable
Original User: vicroads

I have coded up a Python script that determines the coordinates of where I need to create a new (calibration)point, but I can't work out how to add it to a feature class WITH other attributes.

I can create a pointGeometry and add it to a new feature class, as shown here...
http://resources.arcgis.com/en/help/main/10.1/index.html#/PointGeometry/018z00000039000000/

...thus creating points but with no attributes to show what road each point belongs to. But I need to append it to the existing point feature class, or at least add the new points to a new feature class with the desired attribute information.

Any help would be greatly appreciated!
Brett.

GIS platform: ArcGIS 10.1
0 Kudos
5 Replies
markdenil
Occasional Contributor III
Open an Insert Cursor on your existing feature class
create a new row
create a point object at the intended location
pass the point object to the shape field
calculate the attribute fields to the values you fancy
add the row to the table.
repeat as needed.

Alternatly,
Lines and polygons can be built as arrays of points,
and then the array can be passed to the shape field,
then calculate the attributes as above,
by Anonymous User
Not applicable
Original User: Caleb1987

Mark has a good suggestion with using an insert cursor...However, I would like to mention an alternative since I have two versions of the code posted below.  The version shown here (dictionary/create csv/make XY event table) is much faster than the other version which creates point geometry objects with the same attributes in a dictionary and passes them in a new feature class with an insert cursor. 

This is just a simple tool I wrote to get the start and end points of lines and I add a few attributes.  I add the XY data and the attributes to a dictionary then write those values out to a csv. Each csv is then made into an XY event table then convert both to feature classes.  Finally, it will merge the start and end points at the end to create the output feature class.

import arcpy, os, sys, traceback
from os import path as p
from datetime import datetime as d
startTime = d.now()
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = False

def GetStartAndEndOfLine(lines, out_fc, join_field):
    
    # Get geometry objects
    coords = {}
    with arcpy.da.SearchCursor(lines, [join_field, 'SHAPE@', 'SHAPE@LENGTH', 'OID@']) as rows:
        ID = 1
        for row in rows:
            st_x = float(str(row[1].firstPoint).split(' ')[0])
            st_y = float(str(row[1].firstPoint).split(' ')[1])
            end_x = float(str(row[1].lastPoint).split(' ')[0])
            end_y = float(str(row[1].lastPoint).split(' ')[1])
            coords[ID] = [st_x, st_y, end_x, end_y, row[2], row[0],row[3]]
            ID += 1

    # Must create temp csv's for XY Event layer
    tmp = os.getcwd()
    csv_start = p.join(tmp,'temp_start_coords.csv')
    csv_end = p.join(tmp,'temp_end_coords.csv')
    
    # Create Start Csv
    with open(csv_start, 'w') as f:
        f.write('Line_ID,X_Coord,Y_Coord,Length,%s,JOIN_FID,Type\n' %join_field)
        for k,v in coords.iteritems():
            f.write(','.join(str(i) for i in [k,v[0],v[1],v[4],v[5],v[6],'Start']) +'\n')

    # Create End Csv
    with open(csv_end, 'w') as f:
        f.write('Line_ID,X_Coord,Y_Coord,Length,%s,JOIN_FID,Type\n' %join_field)
        for k,v in coords.iteritems():
            f.write(','.join(str(i) for i in [k,v[2],v[3],v[4],v[5],v[6],'End']) +'\n')

    # Get Spatial Reference info
    SR = arcpy.Describe(lines).spatialReference
    
    # Make_XY event layers
    start_xy = arcpy.MakeXYEventLayer_management(csv_start, 'X_Coord', 'Y_Coord', 'Start_xy_lyr', SR)
    end_xy = arcpy.MakeXYEventLayer_management(csv_end, 'X_Coord', 'Y_Coord', 'End_xy_lyr', SR)

    # Create output
    if arcpy.Exists(out_fc):
        arcpy.Delete_management(out_fc)
    arcpy.Merge_management([start_xy, end_xy], out_fc)
        
    # Clean up
    arcpy.Delete_management(csv_start)
    arcpy.Delete_management(csv_end)
    print 'Created "%s"' %p.basename(out_fc)
    arcpy.AddMessage('Created "%s"' %p.basename(out_fc))
                  
    
if __name__ == '__main__':

    try:
        # Script tool params
        # Will try as a script tool first
        #
        lines = arcpy.GetParameterAsText(0)
        points = arcpy.GetParameterAsText(1)
        field = arcpy.GetParameterAsText(2)

        GetStartAndEndOfLine(lines, points, field)
        
    except:
        arcpy.AddMessage('ERROR')
        arcpy.GetMessages(2)

        # if not a script tool will go to stand alone
        # Stand alone testing
        #
        lines = r'C:\Testing\test2.gdb\roads'
        points = r'C:\Testing\test2.gdb\Roads_Points2'
        field = 'NAME1'
    
        GetStartAndEndOfLine(lines, points, field)
        print '(Elapsed time: %s)' %(str(d.now() - startTime)[:-3])



This had a completion time of (Elapsed time: 0:00:02.570)

And here is the version that is more along the lines of what Mark was talking about with using an insert cursor.

import arcpy, os, sys, traceback
from os import path as p
from datetime import datetime as d
startTime = d.now()
arcpy.env.overwriteOutput = True
arcpy.env.qualifiedFieldNames = False

def AddFields(in_fc, field, f_type, length=''):
    # dictionary to get correct input for add field tool
    type_dict = {'String': 'TEXT','SmallInteger':'SHORT',
                 'Integer':'LONG','Single':'FLOAT','Double':'DOUBLE'}
    
    add_fields = {'Line_ID':'LONG','X_Coord':'DOUBLE','Y_Coord':'DOUBLE',
                  'Length':'DOUBLE','JOIN_FID':'LONG',field:type_dict[f_type]}
    for f,t in add_fields.iteritems():
        arcpy.AddField_management(in_fc, f, t, field_length=length)
    arcpy.AddField_management(in_fc, 'Type', 'TEXT', field_length=5)
    
    
def GetStartAndEndOfLine(lines, out_fc, join_field):
    
    # Get geometry objects
    coords = {}
    with arcpy.da.SearchCursor(lines, [join_field, 'SHAPE@', 'SHAPE@LENGTH', 'OID@','SHAPE@XY']) as rows:
        ID = 1
        for row in rows:
            st_x = float(str(row[1].firstPoint).split(' ')[0])
            st_y = float(str(row[1].firstPoint).split(' ')[1])
            end_x = float(str(row[1].lastPoint).split(' ')[0])
            end_y = float(str(row[1].lastPoint).split(' ')[1])
            st_XY = row[1].firstPoint
            end_XY = row[1].lastPoint
            coords[ID] = [st_x, st_y, end_x, end_y, row[2], row[0],row[3],st_XY,end_XY]
            ID += 1

    # Must create temp csv's for XY Event layer
    tmp = 'in_memory'
    start = p.join(tmp,'temp_start')
    end = p.join(tmp,'temp_end')

     # Get Spatial Reference info
    SR = arcpy.Describe(lines).spatialReference
    
    # Get field type
    field_type = [f.type for f in arcpy.ListFields(lines) if f.name == join_field][0]
    if field_type == 'String':
        field_length = [f.length for f in arcpy.ListFields(lines) if f.name == join_field][0]
    else:
        field_length = ''
    
    # Create new FC
    for tmp_fc in [start, end]:
        arcpy.CreateFeatureclass_management(tmp,p.basename(tmp_fc),'POINT','','','',SR)
        AddFields(tmp_fc, join_field, field_type, field_length)

        # Insert new rows
        in_fields = ['Line_ID','X_Coord','Y_Coord','Length',
                     join_field,'JOIN_FID','Type','SHAPE@XY']
        with arcpy.da.InsertCursor(tmp_fc, in_fields) as rows:     
            for k,v in sorted(coords.iteritems()):
                if tmp_fc == start:
                    rows.insertRow((k,v[0],v[1],v[4],v[5],v[6],'Start',v[7]))
                else:
                    rows.insertRow((k,v[2],v[3],v[4],v[5],v[6],'End',v[8]))
                 
    # Create output
    if arcpy.Exists(out_fc):
        arcpy.Delete_management(out_fc)
    arcpy.Merge_management([start, end], out_fc)
    print 'Created "%s"' %p.basename(out_fc)
    arcpy.AddMessage('Created "%s"' %p.basename(out_fc))
                  
    
if __name__ == '__main__':

    try:
        # Script tool params
        lines = arcpy.GetParameterAsText(0)
        points = arcpy.GetParameterAsText(1)
        field = arcpy.GetParameterAsText(2)

        GetStartAndEndOfLine(lines, points, field)
        print '(Elapsed time: %s)' %(str(d.now() - startTime)[:-3])
        
    except:
        arcpy.AddMessage('ERROR')
        arcpy.GetMessages(2)
        
        # Stand alone testing
        lines = r'C:\Testing\test2.gdb\roads'
        points = r'C:\Testing\test2.gdb\Roads_Points'
        field = 'NAME1'
    
        GetStartAndEndOfLine(lines, points, field)
        print '(Elapsed time: %s)' %(str(d.now() - startTime)[:-3])



This was marginally slower though @ (Elapsed time: 0:00:06.740)
0 Kudos
NicholasReseburg1
New Contributor III

I know this is an old thread but i was hoping you could answer, in the  code above, specifically

for k,v in sorted(coords.iteritems()): 

What does the k represent?  I can see the V's are parts of the coords array but i can't figure out what k refers to.

thanks

0 Kudos
DarrenWiens2
MVP Honored Contributor

When in doubt, 'print' to find out:

>>> coords = {}
... coords[1] = ['blah1','blah2']
... coords[2] = ['blah3','blah4']
... for k,v in coords.iteritems():
...    print (k,v)
...   
(1, ['blah1', 'blah2'])
(2, ['blah3', 'blah4'])

k,v is code for key, value.

NicholasReseburg1
New Contributor III

thanks darren!

0 Kudos