16

I've written a python script using arcpy which outputs a polygon feature class into a File Geodatabase. I have added a function to export the attributes to a separate CSV file. I am using the code which I have found in this post which works perfectly. However, that code exports every column in the feature class. I only want to export the fields that do not have the following names: OBJECTID, Shape, or Shape_Length.

My CSV file generates successfully, and it correctly does not include the OBJECTID or Shape_Length fields. However, the Shape field is written to the file. An example value that is written to that field is:

<geoprocessing describe geometry object object at 0x28CB90A0>

I have added a line to print the field names as it iterates through them and surprisingly, Shape is not printed. It's as if ArcGIS is hiding it or gives it a different name.

The code for my function is below:

def exportToTable():
    """ 
        Exports the final outputs to a CSV File.
    """

    # Create path to CSV File (note the varialbe outputPath is declared elsewhere).
    CSVFile = outputPath+'\\FinalOutput.csv'
    arcpy.AddMessage("Created CSV File: %s" %CSVFile)

    # Get all fields in FinalOutput feature class and remove unwanted fields.
    fields = arcpy.ListFields('FinalOutput')
    for field in fields:
        arcpy.AddMessage("Field.name is:"+field.name) #not printing 'Shape' field name
        if field.name in (['OBJECTID', 'Shape', 'Shape_Length']):
            fields.remove(field)

    i = 1
    f=open(CSVFile, 'w')
    for field in fields:
        #--write the wanted field names to the output file
        if i < len(fields):
            f.write('%s,' % field.name)
            i += 1
        else:
            f.write('%s\n' % field.name)

    # Use a search cursor to iterate through the rows of the table and write them to the CSV file.
    rows = arcpy.SearchCursor('FinalOutput')
    for row in rows:
        i = 1
        for field in fields:
            if i < len(fields):
                f.write('%s,' % row.getValue(field.name))
                i += 1
            else:
                f.write('%s\n' % row.getValue(field.name))
    del rows
    f.close()

Does anyone know what's going on here?


I modified my code to follow the advice of @sgrieve and it was still writing the Shape field. If I add a line to print the field names as it iterates through them, it lists all the fields except the Shape field, yet it still writes to the CSV. It also added the X and Y coordinates of the polygon as two new columns and the columns no longer aligned with the column names.

I've modified the line where @sgrieve declares the fields to be the following:

fields = [f.name for f in arcpy.ListFields('FinalCadastre') if f.type <> 'Geometry']

The new code works fine, but I'm still unsure what the problem was. Does anyone know what was going on? What's the deal with the Shape field?

4
  • Do you need to use Python here? It's very easy to hide the fields you don't want using the Fields tab of layer Properties. Then from the open attribute table Export data to Text File (which is CSV) format to get just those fields you do want.
    – PolyGeo
    Commented Nov 28, 2012 at 6:58
  • Yes, I want this to be added to my script. It's a client requirement.
    – Fezter
    Commented Nov 28, 2012 at 7:02
  • Does anyone else know what is going on here? Does anyone know why the Shape field was being written to the file? While @sgrieve's code possibly improved my code, it did not solve the issue.
    – Fezter
    Commented Dec 13, 2012 at 6:13
  • 1
    My approach to this would be to use MakeTableView followed by TableToTable. If your approach does not get there this might be another way to "lose" your Shape field.
    – PolyGeo
    Commented Dec 13, 2012 at 6:30

3 Answers 3

14

I have simplified your code and corrected the error by using the da module introduced in 10.1. It greatly streamlines the reading of data using cursors, and used in conjunction with the with command this code should be more stable than if it used the the older method of file access.

It works by making a list of all the fields and then removing the fields you do not want from the list. This could be done within the list comprehension, but it would be pretty messy and un-pythonic. Once the list of desired fields has been created it is used with the da module to read all of the data in these fields into the cursor. This can then be looped through and written to the file using another list comprehension to join all the fields. This has the benefit of working for any number of fields greater than 0.

import arcpy

fc = 'C:\\antenna_shp\\cables.shp'
CSVFile = 'C:\\antenna_shp\\FinalOutput.csv'

fields = [f.name for f in arcpy.ListFields(fc)]

for i,f in enumerate(fields):
    if f == 'Shape' or f == 'Shape_Length' or f == 'OBJECTID':
        del fields[i]

with open(CSVFile, 'w') as f:
    f.write(','.join(fields)+'\n') #csv headers
    with arcpy.da.SearchCursor(fc, fields) as cursor:
        for row in cursor:
            f.write(','.join([str(r) for r in row])+'\n')
2
  • Thanks @sgrieve. I copied the code you posted and I get a CSV file that is almost what I want. But there are a few issues. 1. The Shape field name is still getting written but the Shape values are not. 2. There are now two new columns that have been added to the beginning of the table effectively shifting the columns to the right. They columns appear to be the X and Y coordinates of the polygon.
    – Fezter
    Commented Nov 28, 2012 at 23:12
  • 3
    Ok, I think I've worked it out. There was something going on with the Shape field - maybe because it is a geometry type. So, I've modified the line where you declare fields to be the following: fields = [f.name for f in arcpy.ListFields('FinalCadastre') if f.type <> 'Geometry'] that did the trick. Not sure why it wasn't working without that though.
    – Fezter
    Commented Nov 29, 2012 at 0:28
2

I think I've run into the same problem and discovered the reason why your field "Shape" was not being removed. When using this loop:

if field.name in (['OBJECTID', 'Shape', 'Shape_Length']):
    fields.remove(field)

I have discovered it is actually only removing every other field. So it will first loop through, remove 'OBJECTID', and then the 'Shape' field goes to the place held previously by 'OBJECTID' in the list, so it moves on to the next one, which would then be 'Shape_Length'.

So it was not specifically the Shape geometry that was preventing it from being removed, just the fact that it removes every other field when using this script.

2
  • Good idea, in which case creating multiple if statements (not elifs) could resolve the issue.
    – Sleep6
    Commented Aug 22, 2014 at 21:37
  • It's not a good idea to mutate a list in a loop. You can get unexpected results. See this post on a similar issue I had.
    – Fezter
    Commented Jun 1, 2017 at 5:16
0

A key to one aspect of this is determining the proper name for the non-user-defined fields of object id and geometry. The type of the geometry field is Double, which is unhelpful in this case. Using the describe function, one can determine the proper name for these fields across file types (i.e. shapefile v file gdb, etc; alleviating a lot of grief as oid will change even within the same file type at times...).

fc = 'path to my featureclass'
desc = arcpy.Describe(fc)
fields = [f.name for f in arcpy.ListFields(fc) if f.name not in (desc.OIDFieldName, desc.areaFieldName, desc.lengthFieldName), desc.shapeFieldName)]

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.