5

I'm pretty sure someone has done this before, but I'm having no luck. I'm using ArcGIS Standard version 10.2.1 and I want to convert all the vertices of a polyline or polygon to points. Essentially, I want to emulate the Feature Vertices to Points tool (which I can't use due to my ArcGIS license). I'm writing a python tool, so any answers should reflect a python/arcpy solution. Therefore, nothing like ET Geowizards, etc.

I want to maintain the fields of the original data and in addition, add X and Y fields as well as a point identifier. So, if the input fields look like this:

LABEL |  TYPE  |  CODE
abc   |  type1 |  3
def   |  type2 |  4

Then the resulting output points might look like this:

LABEL |  TYPE  |  CODE  |  LONG  |  LAT  | ID
abc   |  type1 |  3     |  153   | -27.5 | 1
abc   |  type1 |  3     |  150   | -27.5 | 2
def   |  type2 |  4     |  151   | -30   | 1
def   |  type2 |  4     |  151   | -29.5 | 2
def   |  type2 |  4     |  151   | -30.7 | 3
def   |  type2 |  4     |  151   | -30   | 4

I've looked at this solution, which is fantastic and quick, but it doesn't maintain the fields of the original data. I've also looked at modifying this blog post which seems to be the most promising, but again, I can't figure out how to keep the original fields.

My code looks something like this:

fields = arcpy.ListFields(input_fc)
arcpy.CreateFeatureclass_management(destination_workspace, point_file_name, "POINT")
for field in fields:
    fieldnames.append(field.name)
    if field.type in ('TEXT', 'FLOAT', 'DOUBLE', 'SHORT', 'LONG', 'DATE', 'BLOB', 'RASTER', 'GUID'):
        arcpy.AddField_management(point_file_name, field.name, field.type, field.precision, field.scale, field.length, field.aliasName, field.isNullable)

fieldnames.append("SHAPE@JSON")
cursor = arcpy.da.InsertCursor(output_fc, fieldnames)

with arcpy.da.SearchCursor(input_fc, fieldnames) as c:
        for row in c:
            geom = json.loads(row[-1])
            for path in geom['paths']:
                for pt in path:
                    cursor.insertRow(row[0:-1],pt)

It's failing with the insert cursor. The error message I'm getting is:

Traceback (most recent call last):
File "H:\Python\CreatePoints_v0_2.py", line 60, in cursor.insertRow(row[0:-1],pt) RuntimeError: Cannot find field 'LABEL'

The input feature class has a field called "LABEL". However, it's not adding that label to the created feature class.

Note, I want to convert vertices, not centroids.

I'm probably going about this the wrong way, so if anyone has ideas on how to either modify my code, or point me in another direction, I'd be appreciative.

5
  • I'm still not 100% with ArcPy but from what I can see you're not copying the attributes from the line to the vertex (point) there should be a bunch of GetValue and SetValue statements based on my experience in 9.x insert cursors. Is there more code than what's shown. I'm thinking that the input has a field called LABEL which is renamed to _LABEL in the shapefile as it's a reserved or naughty word for a field name. Apr 16, 2014 at 5:51
  • You've used AddField_management on point_file_name but your InsertCursor is working on output_fc - are you sure that output_fc has the required fields? Apr 16, 2014 at 5:53
  • @StephenLead, good catch. I thought of that. However, earlier, I define 'output_fc = destination_workspace + '\\' + point_file_name'. However, the CreateFeatureclass_management tool takes 'out_path' and 'out_name' which is essentially the same as output_fc. resources.arcgis.com/en/help/main/10.1/index.html#//…
    – Fezter
    Apr 16, 2014 at 6:07
  • It's a bit hard to debug as not all the code is included - can you verify that output_fc contains all required attributes (which I think is what the error message is complaining about)? Can you also break before the with arcpy.da line and check the value of fieldnames? Apr 16, 2014 at 6:14
  • output_fc is not getting any attributes.
    – Fezter
    Apr 16, 2014 at 6:25

2 Answers 2

4

I think you're getting the error because the fieldnames list still contains the field LABEL, but you said you're not adding it to the output_fc.

for field in fields:
    fieldnames.append(field.name)

Right here you're getting all the field names.

If you do a print statement above this line:

cursor = arcpy.da.InsertCursor(output_fc, fieldnames)

I assume you'll see LABEL as a field which was not added to the output_fc.

You should only append the fields that you add to the output_fc.

I would think that this should work:

for field in fields:
    if field.type in ('TEXT', 'FLOAT', 'DOUBLE', 'SHORT', 'LONG', 'DATE', 'BLOB', 'RASTER', 'GUID'):
        arcpy.AddField_management(point_file_name, field.name, field.type, field.precision, field.scale, field.length, field.aliasName, field.isNullable)
        fieldnames.append(field.name)

Unless I'm misunderstanding and the problem is that you aren't able to add the LABEL field to the output_fc.


EDIT

The fields aren't adding because the TEXT is actually "String", DOUBLE is "Double", etc.

Try this:

for field in fields:
    print field.type

And see what the output is. You need to match that.

Here's what field.type returns:

http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//000v0000001p000000

All — All field types are returned. This is the default.
Date — Only field types of Date are returned.
Double — Only field types of Double are returned.
Geometry — Only field types of Geometry are returned.
GUID — Only field types of GUID are returned.
Integer — Only field types of Integer are returned.
OID — Only field types of OID are returned.
Raster — Only field types of Raster are returned.
Single — Only field types of Single are returned.
SmallInteger — Only field types of SmallInteger are returned.
String — Only field types of String are returned.

If I were you, I'd just use the template parameter to add the fields.

CreateFeatureclass_management (out_path, out_name, {geometry_type}, {template}, {has_m}, {has_z}, {spatial_reference})

So you could just put:

arcpy.CreateFeatureclass_management(destination_workspace, point_file_name, "POINT", input_fc, "", "", input_fc)

This will create the new feature class including all the fields in the input feature class and it's spatial reference.

3
  • I edited my post, I think I see what's wrong. The list of field types you have is incorrect.
    – ianbroad
    Apr 16, 2014 at 6:33
  • Thanks @ian. That fixed the Add Fields Part. Now, I just need to fix my insert cursor. A job for tomorrow.
    – Fezter
    Apr 16, 2014 at 6:54
  • @Fezter No problem. I added one more suggestion, using the template parameter in the CreateFeatureclass function.
    – ianbroad
    Apr 16, 2014 at 7:01
3

Just been looking at this thread and followed the link to the other thread which showed Numpy being used. I've personally never used this approach before so I started reading the help file about it and I think this can all be done in 5 lines!

The dataset I tested this on was a polyline layer representing the rivers of the Amazon. So my code is as:

InFc  = "Amazon" # Layer loaded in map
SR = arcpy.Describe(InFc).spatialReference
array = arcpy.da.FeatureClassToNumPyArray(InFc,["*"], spatial_reference=SR, explode_to_points=True)
arcpy.da.NumPyArrayToTable(array,"in_memory/tab")
arcpy.MakeTableView_management("in_memory/tab","myTable")

In your example output you have an extra field called ID which is incremental for the individual feature that has been exploded into its vertices. I created a field of type long and ran the following Field calculate to create this.

Field calculator

You could optionally turn this into an XY event layer.

2
  • I haven't tried this. Does it keep all the fields from the InFc and save them into each record for the new table?
    – ianbroad
    Apr 16, 2014 at 13:23
  • Yes this explodes the geometries and retains the original attribution.
    – Hornbydd
    Apr 16, 2014 at 23:53

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.