I have a feature class layer that comprise of line elements. For my purpose, I needed the start and end point coordinates of each line, so I added new columns with add field and use calculate geometry in ArcGIS Pro to assign the start/end coordinates to each line (below table show the attributes).

What I want to do is that to write a python code that compare lines’ first and end coordinates. Then return a list of IDs for those that their start/end points are equal, and append all those as nested lists in a main list. For instance, if object IDs 2, 5 and 6 have same start and end point, and if object IDs 8, 12, 15 an 22 have the same condition, the code return a nested list like this: main_list = [[2, 5, 6], [8, 12, 15, 22]]. Finally, I want to edit the var column with this outcome. I want var to be equal to length of each corresponding nested list minus one. For instance for those example above, var values for object IDs 2, 5 and 6 will be 2 (length of nested list minus one), and for IDs 8, 12, 15 and 22 will be 3.

ID x_start y_start x_end y_end var
fields = ['ID', 'x_start', 'y_start', 'x_end', 'y_end']
MainList   = [[]]
NestedList = []

ID = [row[0] for row in arcpy.da.SearchCursor(Redundancy_one, ('ID'))]
x_start = [row[0] for row in arcpy.da.SearchCursor(Redundancy_one, ('x_start'))]
y_start = [row[0] for row in arcpy.da.SearchCursor(Redundancy_one, ('y_start'))]
x_end = [row[0] for row in arcpy.da.SearchCursor(Redundancy_one, ('x_end'))]
y_end = [row[0] for row in arcpy.da.SearchCursor(Redundancy_one, ('y_end'))]

i = 0
while i<len(ID):
    with arcpy.da.SearchCursor[Redundancy_one, fields] as cursor:
        for row in cursor:
            if x_start[0] == row[1] and y_start[2] == row[2] and x_end[2] == row[3] and y_end == row[4] and ID[0] =! row[0]:
                NestedList.append (row[0])
    i +=1

1 Answer 1


You can use pandas and arcpy together

#Create a pandas dataframe from your line layer with the columns ID and the line geometry
import pandas as pd
layer = 'lines_starting_ending_same'
fields = ["ID","SHAPE@"]
df = pd.DataFrame(data=arcpy.da.SearchCursor(layer, fields), columns=["id","line"])

#Calculate start and end coordinates for all lines
df["start_x"]=df.apply(lambda x: x.line.firstPoint.X, axis=1)
df["start_y"]=df.apply(lambda x: x.line.firstPoint.Y, axis=1)
df["end_x"]=df.apply(lambda x: x.line.lastPoint.X, axis=1)
df["end_y"]=df.apply(lambda x: x.line.lastPoint.Y, axis=1)

#Group lines having the same start and end coordinates and list their ids
same_start_and_end = df.groupby(["start_x","start_y","end_x","end_y"])["id"].apply(list).reset_index()

#Count them
same_start_and_end["count"] = same_start_and_end.apply(lambda x: len(x["id"]), axis=1)
same_start_and_end["var"] = same_start_and_end["count"]-1

#Then do whatever you want with the result. For example export as a table, or update the values in your lines table

enter image description here

To create a field in the original table with the calculated var value. Create a dictionary and use it with da.UpdateCursor:

#Create a dictionary with id as key and var as value
update_dict = dict(zip(same_start_end["id"], same_start_end["var"]))

#Add an integer field called var
table = r"C:\GIS\data\testdata\lines_starting_ending_same.shp"
arcpy.management.AddField(in_table=table, field_name="var", field_type="SHORT")
#Update it using the dictionary
with arcpy.da.UpdateCursor(table, ["id","var"]) as cursor:
    for row in cursor:
        if row[0] in update_dict:
            row[1] = update_dict[row[0]]

enter image description here

  • 2
    always enjoy reading your responses as I end up learning something new about python. I don't use pandas but have been trying to understand your answer. I guess this is obvious to a pandas user, but looking at your code you create the XY coordinates of the end points using code df["start_x"]=df.apply.... What I can't get my head around is where is "start_x", you don't seem to have created that before you populate it with data? Is this a behaviour of pandas, if you reference a field name that does not exist in the data frame it is simultaneously created and populated?
    – Hornbydd
    Commented Mar 2, 2023 at 16:51
  • 1
    :). .Yes that is the standard way of creating a new column. Pandas is great, you can do almost anything with the data. A thing like that, creating a new column is very simple.
    – Bera
    Commented Mar 2, 2023 at 17:54
  • 1
    Thanks a lot for your help @BERA. I was wondering why the length of initial and final my data frame is different. I had 859 before using the code but 783 after that? I guess there shouldn't be any differences.
    – rez
    Commented Mar 3, 2023 at 3:54
  • 1
    It should be beacuse of the grouping. In my example the three rows 1,2,3 become one. If you want the same row count you can explode
    – Bera
    Commented Mar 3, 2023 at 6:09
  • 1
    Yes, see the update
    – Bera
    Commented Mar 10, 2023 at 6:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.