Using Python to create line segments from coordinates

13046
9
Jump to solution
01-30-2015 06:48 AM
GeoffOlson
Occasional Contributor

I'm working on manipulating point coordinates into line segments.  I have a series of GPS track points that I'm trying to get into individual links.  Each line will only have a starting vertex and and ending vertex.  I was successful in loading each point, starting with the second point, in copying the X,Y coordinates from the prior point.  For example, point 2 has its GPS location in and X and Y column and it has the coordinate from point 1 in two other X and Y columns, point 3 has its X,Y values and the values from point 2.  This has given me both the starting and ending coordinates.

I tried using the sample Python script from the help file, but it seems to skip segments.  The only thing I can think is happening is that the X1 and Y1 and loading in as the same as X2 and Y2, so there is no line to be drawn, yet a feature is created.  The other problem I've run into is that the vertices of the lines don't overlap the points. 

mxd = arcpy.mapping.MapDocument("Current")# Define mxd to current file.


mapLyr1 = arcpy.mapping.ListLayers(mxd, "test_points") [0]


feature_info = list()


with arcpy.da.UpdateCursor(mapLyr1,["FID","Latitude", "Longitude", "E_Lat", "E_Long"]) as sCursor:
    for row in sCursor:
  if row[0] == 0:
  lastLat = row[1]
  lastLong = row[2]
  else:
  thisLat = row[1]
  thisLong = row[2]
  row[3] = lastLat
  row[4] = lastLong
  sCursor.updateRow(row)
  Coords = [[thisLong, thisLat], [lastLong, lastLat]]#creates the X1, Y1 and X2, Y2 pairs
  print Coords
  feature_info.append(Coords)#append the X,Y pairs
  lastLat = thisLat#turn current Y value into past Y value
  lastLong = thisLong#turn current X value into past X value




#Loops through layer to create list of X,Y Pairs
with arcpy.da.SearchCursor(mapLyr1, ["Longitude", "Latitude", "E_Long", "E_Lat"]) as lineMaker:
  for points in lineMaker:
  p1, p2, p3, p4 = points[0], points[1], points[2], points[3]
  pairs = [[p1, p2], [p3, p4]]
  feature_info.append(pairs)


features = []
#Snippet from Help/ESRI Resources
for feature in feature_info:
    # Create a Polyline object based on the array of points
    # Append to the list of Polyline objects
    features.append(
        arcpy.Polyline(
            arcpy.Array([arcpy.Point(*coords) for coords in feature])))


# Persist a copy of the Polyline objects using CopyFeatures
arcpy.CopyFeatures_management(features, "c:/temp/polylines.shp")

I end up with the features looking like this:

Clipboard02.jpg

I'm not sure if this is a scripting error alone, or if projections are playing a part too.  If it were a projection issue, then all the lines would show up.  I expect that if it were only a scripting error, all the points and lines would coincide.

0 Kudos
1 Solution

Accepted Solutions
GeoffOlson
Occasional Contributor

Thanks for the posts, you guys were right about the spatial reference problem.  All I did was add that bit to the array function in my original script and it works great!  Thanks for the help!

mxd = arcpy.mapping.MapDocument("Current")# Define mxd to current file.


mapLyr1 = arcpy.mapping.ListLayers(mxd, "test_points") [0]


feature_info = list()


with arcpy.da.UpdateCursor(mapLyr1,["FID","Latitude", "Longitude", "E_Lat", "E_Long"]) as sCursor:
    for row in sCursor:
  if row[0] == 0:
  lastLat = row[1]
  lastLong = row[2]
  else:
  thisLat = row[1]
  thisLong = row[2]
  row[3] = lastLat
  row[4] = lastLong
  sCursor.updateRow(row)
  Coords = [[thisLong, thisLat], [lastLong, lastLat]]#creates the X1, Y1 and X2, Y2 pairs
  print Coords
  feature_info.append(Coords)#append the X,Y pairs
  lastLat = thisLat#turn current Y value into past Y value
  lastLong = thisLong#turn current X value into past X value




#Loops through layer to create list of X,Y Pairs
with arcpy.da.SearchCursor(mapLyr1, ["Longitude", "Latitude", "E_Long", "E_Lat"]) as lineMaker:
  for points in lineMaker:
  p1, p2, p3, p4 = points[0], points[1], points[2], points[3]
  pairs = [[p1, p2], [p3, p4]]
  feature_info.append(pairs)


features = []
#Snippet from Help/ESRI Resources
for feature in feature_info:
    # Create a Polyline object based on the array of points
    # Append to the list of Polyline objects
    features.append(
        arcpy.Polyline(
            arcpy.Array([arcpy.Point(*coords) for coords in feature]),arcpy.SpatialReference(4326)))


# Persist a copy of the Polyline objects using CopyFeatures
arcpy.CopyFeatures_management(features, "c:/temp/polylines.shp")

View solution in original post

0 Kudos
9 Replies
XanderBakker
Esri Esteemed Contributor

I changed the code a little to not use a layer in ArcMap, but rather the source on disk.

You should change the location of the input on line 4.

In case you are using a table as input you should comment line 14 and uncomment line 15 and specify the sr your input coordinates have (4326 is WGS84, decimal degrees).

import arcpy

# location of input and output
fc_in = r"C:\temp\test_points.shp" # or .dbf, or ?
fc_out = r"C:\temp\polylines.shp"

fld_lat_in = "Latitude"
fld_lon_in = "Longitude"
fld_lat_out = "E_Lat"
fld_lon_out = "E_Long"

flds = (fld_lat_in, fld_lon_in, fld_lat_out, fld_lon_out)

sr = arcpy.Describe(fc_in).spatialReference # if input is a featureclass, or:
# sr = arcpy.SpatialReference(4326) # where 4326 represents the WKID of the coordinate system

features = []
cnt = 0
with arcpy.da.UpdateCursor(fc_in, flds) as curs:
    for row in curs:
        cnt += 1
        if cnt == 1:
            lastLat = row[1]
            lastLong = row[2]
        else:
            thisLat = row[1]
            thisLong = row[2]
            row[3] = lastLat
            row[4] = lastLong
            curs.updateRow(row)
            features.append(arcpy.Polyline(arcpy.Array(
                        [arcpy.Point(lastLong, lastLat),
                        arcpy.Point(thisLong, thisLat)])), sr) # provide sr
            lastLat = thisLat # turn current Y value into past Y value
            lastLong = thisLong # turn current X value into past X value

del curs, row

# Persist a copy of the Polyline objects using CopyFeatures
arcpy.CopyFeatures_management(features, fc_out)
GeoffOlson
Occasional Contributor

I had to add a couple brackets and parentheses to the Array/Point line to get it to run, but I receive this error:

Runtime error

Traceback (most recent call last):

  File "<string>", line 55, in <module>

  File "c:\program files (x86)\arcgis\desktop10.2\arcpy\arcpy\management.py", line 2429, in CopyFeatures

    raise e

RuntimeError: Object: Error in executing tool

Here's the updated script

import arcpy


# location of input and output
fc_in = r"C:\temp\test_points.shp" # or .dbf, or ?
fc_out = r"C:\temp\polylines.shp"


FID = "FID"
fld_lat_in = "Latitude"
fld_lon_in = "Longitude"
fld_lat_out = "E_Lat"
fld_lon_out = "E_Long"


flds = (FID, fld_lat_in, fld_lon_in, fld_lat_out, fld_lon_out)


sr = arcpy.Describe(fc_in).spatialReference # if input is a featureclass, or:
# sr = arcpy.SpatialReference(4326) # where 4326 represents the WKID of the coordinate system


features = []
cnt = 0
with arcpy.da.UpdateCursor(fc_in, flds) as curs:
    for row in curs:
        cnt += 1
        if cnt == 1:
            lastLat = row[1]
            lastLong = row[2]
        else:
            thisLat = row[1]
            thisLong = row[2]
            row[3] = lastLat
            row[4] = lastLong
            curs.updateRow(row)
            features.append([arcpy.Polyline(arcpy.Array([arcpy.Point(lastLong, lastLat), arcpy.Point(thisLong, thisLat)])), sr]) # provide sr
            lastLat = thisLat # turn current Y value into past Y value
            lastLong = thisLong # turn current X value into past X value


del curs, row


# Persist a copy of the Polyline objects using CopyFeatures
arcpy.CopyFeatures_management(features, fc_out)
0 Kudos
XanderBakker
Esri Esteemed Contributor

There were some issues with the script that I noticed when I actually run the code:

  • Indexes to fields in row were from 1 to 4, should be 0 to 3
  • the spatial reference in the polyline, was at the wrong location.

Just did a test based on a dbf table with the coordinates and this is the result:

result.png

Code:

import arcpy

# location of input and output
fc_in = r"C:\Forum\LineFromTbl\Coords.dbf" # or .dbf, or ?
fc_out = r"C:\Forum\LineFromTbl\polylines1.shp"

fld_lat_in = "Latitude"
fld_lon_in = "Longitude"
fld_lat_out = "E_Lat"
fld_lon_out = "E_Long"

flds = (fld_lat_in, fld_lon_in, fld_lat_out, fld_lon_out)

# sr = arcpy.Describe(fc_in).spatialReference # if input is a featureclass, or:
sr = arcpy.SpatialReference(4326) # where 4326 represents the WKID of the coordinate system

features = []
cnt = 0
with arcpy.da.UpdateCursor(fc_in, flds) as curs:
    for row in curs:
        cnt += 1
        if cnt == 1:
            lastLat = row[0]
            lastLong = row[1]
        else:
            thisLat = row[0]
            thisLong = row[1]
            row[2] = lastLat
            row[3] = lastLong
            curs.updateRow(row)
            features.append(arcpy.Polyline(arcpy.Array(
                        [arcpy.Point(lastLong, lastLat),
                        arcpy.Point(thisLong, thisLat)]), sr)) # provide sr
            lastLat = thisLat # turn current Y value into past Y value
            lastLong = thisLong # turn current X value into past X value
del curs, row

# Persist a copy of the Polyline objects using CopyFeatures
arcpy.CopyFeatures_management(features, fc_out)
0 Kudos
DanPatterson_Retired
MVP Emeritus

if you haven't used or specified a coordinate system for the output file...expect the unexpected, there are numerous threads on geometry errors when the coordinate system is either unknown or not specified.,..then follow Xander's code example.

GeoffOlson
Occasional Contributor

Thanks for the posts, you guys were right about the spatial reference problem.  All I did was add that bit to the array function in my original script and it works great!  Thanks for the help!

mxd = arcpy.mapping.MapDocument("Current")# Define mxd to current file.


mapLyr1 = arcpy.mapping.ListLayers(mxd, "test_points") [0]


feature_info = list()


with arcpy.da.UpdateCursor(mapLyr1,["FID","Latitude", "Longitude", "E_Lat", "E_Long"]) as sCursor:
    for row in sCursor:
  if row[0] == 0:
  lastLat = row[1]
  lastLong = row[2]
  else:
  thisLat = row[1]
  thisLong = row[2]
  row[3] = lastLat
  row[4] = lastLong
  sCursor.updateRow(row)
  Coords = [[thisLong, thisLat], [lastLong, lastLat]]#creates the X1, Y1 and X2, Y2 pairs
  print Coords
  feature_info.append(Coords)#append the X,Y pairs
  lastLat = thisLat#turn current Y value into past Y value
  lastLong = thisLong#turn current X value into past X value




#Loops through layer to create list of X,Y Pairs
with arcpy.da.SearchCursor(mapLyr1, ["Longitude", "Latitude", "E_Long", "E_Lat"]) as lineMaker:
  for points in lineMaker:
  p1, p2, p3, p4 = points[0], points[1], points[2], points[3]
  pairs = [[p1, p2], [p3, p4]]
  feature_info.append(pairs)


features = []
#Snippet from Help/ESRI Resources
for feature in feature_info:
    # Create a Polyline object based on the array of points
    # Append to the list of Polyline objects
    features.append(
        arcpy.Polyline(
            arcpy.Array([arcpy.Point(*coords) for coords in feature]),arcpy.SpatialReference(4326)))


# Persist a copy of the Polyline objects using CopyFeatures
arcpy.CopyFeatures_management(features, "c:/temp/polylines.shp")
0 Kudos
XanderBakker
Esri Esteemed Contributor

Hi Geoff,

First of all glad that you solved your problem. You should however take care when pasting the code to the thread. The indent are very important for the code to be valid. The code you posted and marked as the correct answer is not valid:

CodeError.png

This should be:

CodeOK.png

etc...

You are using 3 loops for something that you can (and should) do in a single loop. If the the code I provided is generating an error, please provide a sample of the data and I will correct it. Just to be sure that the thread has a working code sample for other users that may have a similar problem.

0 Kudos
GeoffOlson
Occasional Contributor

Sorry about that.  It's an issue with the code formatting of the forum, I think, because I pasted it directly from Notepad++ which has all the correct indentation.

I don't know what the error pertains to with the code you provided, just that there was a syntax error with this line:

features.append(arcpy.Polyline(arcpy.Array( [arcpy.Point(lastLong, lastLat),  arcpy.Point(thisLong, thisLat)])), sr)

0 Kudos
XanderBakker
Esri Esteemed Contributor

The formatting of code in GeoNet is OK, but may depend on your browser (I use Chrome without problems).

NotePad++ is not the best choice for writing code. You may have used tabs and spaces for indentation... Best download something like PyScripter which is free and easy to use:

Downloads - pyscripter - An open-source Python Integrated Development Environment (IDE) - Google Pro...

0 Kudos
GeoffOlson
Occasional Contributor

I do use PyScripter for running processes but I haven't figured out how to turn off the auto-complete, particlularly for quotes and the like, which drives me crazy trying to type code.  That's why I usually write in Notepad++.

0 Kudos