arcpy.da.InsertCursor only inserting last row in list of data

3933
18
Jump to solution
10-17-2017 01:40 PM
HannesZiegler2
Frequent Contributor

Hello, I'm working on a script that gathers a bunch of line geometry (created using arcpy.Polyline function) into a list (called lines in the script), and then inserts this geometry into an empty polygon featureclass (called outln_m in the script). However, for some reason, only the last item in the list is there in the output polyline featureclass after the script runs, and I'm baffled. Can anyone shed some light on what might be causing this? I checked and all my cursor/row objects are being deleted before creating a new cursor. I tried wrapping the whole thing in an editor session but that did not change the result.

And the result of my debugging print statements:

You can see the list contains 25 items, but only one record is written to the output featureclass after running the list through a for-loop. That record happens to always be the last item in the list.

Thank you for any help! I'm sure I'm missing something obvious.. I just can't see it.

1 Solution

Accepted Solutions
HannesZiegler2
Frequent Contributor

Okay, I've found the problem, and it's not a bug or anything complicated, just an oversight. Earlier in the script, in order to minimize processing time I set a custom extent around each input point to work with only a small piece of the larger input raster. I forgot to reset the extent to arcpy.env.extent = "MAXOF" at the end of this processing, and so it was stuck on the extent of the last item processed. GetCount and InterpolateShape both honor the processing extent, while the InsertCursor (or rather the list of geometry objects I feed it) does not. Problem solved.

*EDIT 10/24/2017*

^ I was in a rush when I posted this, thank you all for the suggestions and help on cracking this!

View solution in original post

18 Replies
JoshuaBixby
MVP Esteemed Contributor

Sharing with Python‌ for more visibility since this is ArcPy related.

Can you share a bit more about your geometries?  The fact that the __repr__ shows "geoprocessing describe ..." makes me think you don't have ArcPy geometries since they typical have a __repr__ of "Polyline object at...".

0 Kudos
HannesZiegler2
Frequent Contributor

Hi Joshua, yupp. The entire script is tool long I think, here are the relevant excerpts:

First I create empty lists (including one for lines), then I start a cursor to go through a points featureclass and find start and end points for a transect line I draw. Then I produce the line array object using those points. 

  1. ##Step through each point in temp_inpt_lyr.  
  2. arcpy.AddMessage("Stepping through each top of dam point and finding bottom of dam point and corresponding elevation...")  
  3. bt_points, txt_data, lines = [], [], [] ##bottom points geometry, output data for csv table, and line geometry are stored in these lists.  
  4. cursor = arcpy.da.SearchCursor(temp_inpt_lyr, ["START_X""START_Y""UNIT_VECTOR_X""UNIT_VECTOR_Y", fid])  
  5. for row in cursor:  
  6.     arcpy.AddMessage(row[4]) ##Print the dam id for current point.  
  7.     st_point = arcpy.Point(row[0], row[1]) ##starting point (START_X, START_Y).  
  8.     ed_point = arcpy.Point(linext*row[2]+row[0], linext*row[3]+row[1]) ##Point at end of line drawn from st_point to linext map units in the opposite direction of the line from the same point to the nearest polygon (of dam surface area) using unit vector.  
  9.     line_arr = arcpy.Array([st_point, ed_point]) ##Array object to contain the st_point and ed_point coordinates that define the transect line used to profile the dam and identify the bottom of dam.  

I then do some other stuff that isn't relevant to the lines geometry (just a bunch of processing reading the geometry and using data from it).

Then I use vectors to find a new point, and more importantly for the problem I'm having, I copy create a line object that contains the line geometry and append that to the lines list. After this it goes into the code in my original post.

  1. magnitude = slp_profile[bod][0] ##Find magnitude for vector bod.  
  2. bt_points.append([arcpy.Point(magnitude*row[2]+st_point.X, magnitude*row[3]+st_point.Y), row[4], elv_profile[bod][1]]) ##Store bottom of dam point geometry, DAMNO, and elevation in list bt_points.  
  3. line = arcpy.Polyline(line_arr, temp_inpt_lyr_spref) ##Have to create line object anew, not sure why but line object loses information after being input into InterpolateShape tool.  
  4. lines.append([line, row[4]]) ##Add lines to polyline geometry for output transect featureclass.  

Code in my original post (plus a little extra setting up fields).

  1. ##Create output featureclass to be populated with transect lines moving away from dams in downstream direction  
  2. arcpy.AddMessage("Writing output transect line featureclass")  
  3. outln_m = arcpy.management.CreateFeatureclass("in_memory""{}_Transect".format(outpt_name), "POLYLINE", spatial_reference = temp_inpt_lyr_spref)  
  4. arcpy.management.AddField(outln_m, fid, "TEXT", field_length = 6)  
  5.   
  6. arcpy.AddMessage(lines)  
  7. arcpy.AddMessage(len(lines)) #DEBUG#  
  8. ##Populate output transect line featureclass  
  9. workspace = r"in_memory"  
  10. with arcpy.da.Editor(workspace) as edit:  
  11.     cursor = arcpy.da.InsertCursor(outln_m, ["SHAPE@", fid])  
  12.     for row in lines:  
  13.         arcpy.AddMessage(row) #DEBUG#  
  14.         cursor.insertRow(row)  
  15. del cursor, row  
  16. arcpy.AddMessage(arcpy.management.GetCount(outln_m)) #DEBUG#  

 

Sorry, it's a lot of code.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

In-memory workspaces aren't full blown workspaces, i.e., they don't support all of the functionality of geodatabase workspaces.  Just to rule out something with using in-memory workspaces, try dumping everything to a file geodatabase.

HannesZiegler2
Frequent Contributor

I'm trying that at the moment, I'm seeing some odd behavior.. I have saved the outln featureclass to a geodatabase instead of in_memory, and when I print GetCount() after running through the InsertCursor, there are 0 features. But.. when I look at this featureclass in my geodatabase there are 25 records, one for each item in the list lines. Now.. I'm using outln as input to InterpolateShape to create a 3D Line, and the output of that tool is still empty, just as the GetCount() print statement suggests. Something really strange is going on.

  1. ##Create output featureclass to be populated with transect lines moving away from dams in downstream direction  
  2. arcpy.AddMessage("Writing output transect line featureclass")  
  3. outln = arcpy.management.CreateFeatureclass(outpt_path, "{}_Transect_Temp".format(outpt_name), "POLYLINE", spatial_reference = temp_inpt_lyr_spref)  
  4. arcpy.management.AddField(outln, fid, "TEXT", field_length = 6)  
  5.   
  6. arcpy.AddMessage(len(lines)) #DEBUG#  
  7. ##Populate output transect line featureclass  
  8. cursor = arcpy.da.InsertCursor(outln, ["SHAPE@", fid])  
  9. for row in lines:  
  10.     arcpy.AddMessage(row) #DEBUG#  
  11.     cursor.insertRow(row)  
  12. arcpy.AddMessage(arcpy.management.GetCount(outln)) #DEBUG#  
  13. arcpy.ddd.InterpolateShape(indem, outln, r"{}\{}_Transect".format(outpt_path, outpt_name))  
  14. del row, cursor  
0 Kudos
JoshuaBixby
MVP Esteemed Contributor

Try deleting the row and cursor before running the InterpolateShape tool.  I have found sometimes there is a delay in flushing the cursor back to disk.

0 Kudos
HannesZiegler2
Frequent Contributor

Tried it, but the problem persists. I thought the with.. as.. statement will automatically clear the cursor and row? 

  1. ##Create output featureclass to be populated with bottom of dam points, dam id, and elevation  
  2. arcpy.AddMessage("Writing output dam elevation featureclass")  
  3. outpt = arcpy.management.CreateFeatureclass(outpt_path, "{}_BottomOfDam".format(outpt_name), "POINT", spatial_reference = temp_inpt_lyr_spref)  
  4. arcpy.management.AddField(outpt, fid, "TEXT", field_length = 6)  
  5. arcpy.management.AddField(outpt, "BottomOfDam_Elevation""DOUBLE")  
  6.   
  7. ##Populate output bottom of dam point featureclass  
  8. with arcpy.da.InsertCursor(outpt, ["SHAPE@", fid, "BottomOfDam_Elevation"]) as cursor:  
  9.     for row in bt_points:  
  10.         cursor.insertRow(row)  
  11. del cursor, row  
  12.   
  13. ##Create output featureclass to be populated with transect lines moving away from dams in downstream direction  
  14. arcpy.AddMessage("Writing output transect line featureclass")  
  15. outln = arcpy.management.CreateFeatureclass(outpt_path, "{}_Transect_Temp".format(outpt_name), "POLYLINE", spatial_reference = temp_inpt_lyr_spref)  
  16. arcpy.management.AddField(outln, fid, "TEXT", field_length = 6)  
  17.   
  18. ##Populate output transect line featureclass  
  19. with arcpy.da.InsertCursor(outln, ["SHAPE@", fid]) as cursor:  
  20.     for row in lines:  
  21.         cursor.insertRow(row)  
  22. del cursor, row  
  23.   
  24. arcpy.ddd.InterpolateShape(indem, outln, r"{}\{}_Transect".format(outpt_path, outpt_name)) 
0 Kudos
MitchHolley1
MVP Regular Contributor

You shouldn't loop over an insert cursor.  Instead, set the cursor to a variable and pass each item of your list to the variable to execute. 

items = ['item1','item2','item3']

cursor = arcpy.da.InsertCursor(fc, ['fields'])

for item in items:
    cursor.insertRow(item)

del cursor
0 Kudos
MitchHolley1
MVP Regular Contributor

Can you send a screenshot of the contents of the lines list?  

0 Kudos
HannesZiegler2
Frequent Contributor

Hi Holley, the contents of the list is printed out by the script (one line per item in the list) as seen in my original post. I've added a print statement for the raw list as well, see below:

Thank you!