¿Exportar solo ciertas columnas a un archivo CSV en ArcGIS for Desktop?

15

He escrito un script de Python usando arcpy que genera una clase de entidad poligonal en una Geodatabase de archivos. He agregado una función para exportar los atributos a un archivo CSV separado. Estoy usando el código que he encontrado en esta publicación que funciona perfectamente. Sin embargo, ese código exporta todas las columnas de la clase de entidad. Sólo quiero exportar los campos que no tienen los siguientes nombres: OBJECTID, Shapeo Shape_Length.

Mi archivo CSV se genera correctamente y no incluye correctamente los campos OBJECTIDo Shape_Length. Sin embargo, el Shapecampo se escribe en el archivo. Un valor de ejemplo que se escribe en ese campo es:

<geoprocessing describe geometry object object at 0x28CB90A0>

He agregado una línea para imprimir los nombres de los campos a medida que los recorre y, sorprendentemente, Shapeno se imprime. Es como si ArcGIS lo estuviera ocultando o le diera un nombre diferente.

El código para mi función está abajo:

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()

¿Alguien sabe lo que está pasando aquí?


Modifiqué mi código para seguir el consejo de @sgrieve y todavía estaba escribiendo el Shapecampo. Si agrego una línea para imprimir los nombres de los campos a medida que los recorre, enumera todos los campos excepto el Shapecampo, pero aún escribe en el CSV. También agregó las coordenadas X e Y del polígono como dos nuevas columnas y las columnas ya no están alineadas con los nombres de las columnas.

Modifiqué la línea donde @sgrieve declara que los campos son los siguientes:

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

El nuevo código funciona bien, pero aún no estoy seguro de cuál era el problema. ¿Alguien sabe lo que estaba pasando? ¿Cuál es el trato con el Shapecampo?

Fezter
fuente
¿Necesitas usar Python aquí? Es muy fácil ocultar los campos que no desea utilizando la pestaña Campos de Propiedades de capa. Luego, desde la tabla de atributos abierta, Exportar datos al formato de archivo de texto (que es CSV) para obtener solo los campos que desea.
PolyGeo
Sí, quiero que esto se agregue a mi script. Es un requisito del cliente.
Fezter
¿Alguien más sabe lo que está pasando aquí? ¿Alguien sabe por qué el Shapecampo se estaba escribiendo en el archivo? Si bien el código de @ sgrieve posiblemente mejoró mi código, no resolvió el problema.
Fezter
1
Mi enfoque para esto sería usar MakeTableView seguido de TableToTable . Si su enfoque no llega allí, esta podría ser otra forma de "perder" su campo Shape.
PolyGeo

Respuestas:

14

He simplificado su código y corregido el error utilizando el módulo da introducido en 10.1. Agiliza en gran medida la lectura de datos utilizando cursores, y junto con el withcomando, este código debería ser más estable que si utilizara el método anterior de acceso a archivos.

Funciona haciendo una lista de todos los campos y luego eliminando los campos que no desea de la lista. Esto podría hacerse dentro de la comprensión de la lista, pero sería bastante desordenado y poco pitónico. Una vez que se ha creado la lista de campos deseados, se utiliza con el módulo da para leer todos los datos de estos campos en el cursor. Esto se puede recorrer y escribir en el archivo utilizando otra comprensión de la lista para unir todos los campos. Esto tiene el beneficio de trabajar para cualquier número de campos mayores que 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')
sgrieve
fuente
Gracias @sgrieve. Copié el código que publicaste y obtengo un archivo CSV que es casi lo que quiero. Pero hay algunos problemas. 1. El Shapenombre del campo todavía se está escribiendo pero los valores de Forma no. 2. Ahora hay dos nuevas columnas que se han agregado al comienzo de la tabla desplazando efectivamente las columnas a la derecha. Las columnas parecen ser las coordenadas X e Y del polígono.
Fezter
33
Ok, creo que lo he resuelto. Algo estaba sucediendo con el Shapecampo, tal vez porque es un tipo de geometría. Entonces, modifiqué la línea donde declaras fieldsser la siguiente: fields = [f.name for f in arcpy.ListFields('FinalCadastre') if f.type <> 'Geometry'] eso funcionó. Sin embargo, no estoy seguro de por qué no estaba funcionando sin eso.
Fezter
2

Creo que me he encontrado con el mismo problema y descubrí la razón por la cual su campo "Forma" no se eliminaba. Al usar este bucle:

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

He descubierto que en realidad solo está eliminando cualquier otro campo. Por lo tanto, primero pasará, eliminará 'OBJECTID', y luego el campo 'Forma' irá al lugar que anteriormente tenía 'OBJECTID' en la lista, por lo que pasará al siguiente, que luego sería 'Shape_Length'.

Por lo tanto, no era específicamente la geometría de la Forma lo que impedía que se eliminara, solo el hecho de que elimina cualquier otro campo al usar este script.

Sara Flecher
fuente
Buena idea, en cuyo caso crear múltiples sentencias if (no elifs) podría resolver el problema.
Sleep6
No es una buena idea mutar una lista en un bucle. Puedes obtener resultados inesperados. Vea esta publicación sobre un problema similar que tuve.
Fezter
0

Una clave para un aspecto de esto es determinar el nombre apropiado para los campos no definidos por el usuario de id. De objeto y geometría. El tipo del campo de geometría es Doble, lo que no es útil en este caso. Usando la función describe, se puede determinar el nombre apropiado para estos campos en todos los tipos de archivo (es decir, shapefile v file gdb, etc.; aliviando mucho dolor como oid cambiará incluso dentro del mismo tipo de archivo a veces ...).

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)]
David Richey
fuente