Select to view content in your preferred language

Creating Feature Class

2849
6
12-09-2014 07:54 AM
deleted-user-Pi5x1UjkS2PY
Deactivated User

I am using     arcpy.da.NumPyArrayToFeatureClass(npyarr, out_fc, ['LONGITUDE','LATITUDE'], sr) to create a shape file but it is removing my Latitude and Longitude fields which I want to include in my JavaScript table.  Not sure why it is doing this.  It creates my shapefile but removes these two columns.  Anyway you know of that I can keep them.

Here is my dtype:

[('YEAR', '<i4'), ('REGIONID', '<i4'), ('DISTRICTID', '<i4'), ('REGIONNAME', '|S255'), ('DISTRICTNAME', '|S255'), ('DIVLOC', '|S255'), ('STORENAME', '|S255'), ('CLUSTER', '|S255'), ('SUBID', '|S255'), ('SUBNAME', '|S255'), ('SEQUENCE', '<i4'), ('S_AREA', '<i4'), ('FS_AREA', '<i4'), ('ST_AREA', '<i4'), ('FR_AREA', '<i4'), ('SO_AREA', '<i4'), ('SL_AREA', '<i4'), ('TOTALSALES', '<i4'), ('OWNEDSALES', '<i4'), ('LEASEDSALES', '<i4'), ('GM', '<i4'), ('PROD', '<i4'), ('GMPROD', '<i4'), ('LATITUDE', '<f8'), ('LATITUDE1', '<f8'), ('LONGITUDE', '<f8'), ('LONGITUDE1', '<f8'), ('RANKSALESSUB', '<i4'), ('RANKPRODSUB', '<i4'), ('RANKSALESSUBD', '<i4'), ('RANKPRODSUBD', '<i4'), ('RANKSALESSUBR', '<i4'), ('RANKPRODSUBR', '<i4'), ('RANKSALESSUBS', '<i4'), ('RANKPRODSUBS', '<i4'), ('RANKSALESSUBC', '<i4'), ('RANKPRODSUBC', '<i4')]

## the important code

   datarray = []

    #for row in cursor:

    for row in cursor.fetchall():

        datarray.append(tuple(row))

    dtype = np.dtype(eval(get_dtype))

    WKID = 4326 # WGS-1984
    sr = arcpy.SpatialReference()
    sr.factoryCode = WKID
    sr.create()
    env.outputCoordinateSystem = sr

    npyarr = np.array(datarray, dtype)
    out_fc = strFilePath + strShapeFileName

    if arcpy.Exists(out_fc):
        arcpy.Delete_management(out_fc)
        arcpy.Delete_management("in_memory")
    env.overwriteOutput = 1

    arcpy.da.NumPyArrayToFeatureClass(npyarr, out_fc, ['LONGITUDE','LATITUDE'], sr)

0 Kudos
6 Replies
JoshuaBixby
MVP Esteemed Contributor

By default, or at least in my experience, NumPyArrayToFeatureClass doesn't include the shape fields as attribute fields in the output feature class.  If you want LatLong as attributes as well, copy the columns and give the new columns a different name, and either use the new columns or the original as the shape fields with the other set getting incorporated as attributes.

deleted-user-Pi5x1UjkS2PY
Deactivated User

I tried to do that but then I got a duplicate field error with the array.   I'm pulling the fields and values from a database via DSN connection to create the arrary..

It is possible I misunderstand what you are suggesting as well so do you have a quick example you can provide?

[('YEAR', '<i4'), ('REGIONID', '<i4'), ('DISTRICTID', '<i4'), ('REGIONNAME', '|S255'), ('DISTRICTNAME', '|S255'), ('DIVLOC', '|S255'), ('STORENAME', '|S255'), ('CLUSTER', '|S255'), ('SUBID', '|S255'), ('SUBNAME', '|S255'), ('SEQUENCE', '<i4'), ('S_AREA', '<i4'), ('FS_AREA', '<i4'), ('ST_AREA', '<i4'), ('FR_AREA', '<i4'), ('SO_AREA', '<i4'), ('SL_AREA', '<i4'), ('TOTALSALES', '<i4'), ('OWNEDSALES', '<i4'), ('LEASEDSALES', '<i4'), ('GM', '<i4'), ('PROD', '<i4'), ('GMPROD', '<i4'), ('LATITUDE', '<f8'), ('LATITUDE1', '<f8'), ('LONGITUDE', '<f8'), ('LONGITUDE1', '<f8'), ('RANKSALESSUB', '<i4'), ('RANKPRODSUB', '<i4'), ('RANKSALESSUBD', '<i4'), ('RANKPRODSUBD', '<i4'), ('RANKSALESSUBR', '<i4'), ('RANKPRODSUBR', '<i4'), ('RANKSALESSUBS', '<i4'), ('RANKPRODSUBS', '<i4'), ('RANKSALESSUBC', '<i4'), ('RANKPRODSUBC', '<i4')]

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

You can take the geoprocessing route as Xander Bakker‌ suggests.  If you want a pure Python/NumPy solution, please post a bit more information.  You say you are getting a duplicate field error with the array, but what method or function is returning the error?  I didn't catch it at first, but your original dtype had a Lat and Lat1 as well as a Long and Long1.  Do those represent different lats and longs or duplicates?

You mentioned pulling this data from a database through a DSN connection to create the array.  Would it work to connect to the table and use the MakeXYEventLayer_management to make an event layer that you can save to disk afterwards.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

A quick code example....

There are various ways to add fields to structured numpy arrays.  Although it might not be the most performant, I typically use a solution proposed by Vebjorn Ljosa on StackExchange:  Adding a field to a structured numpy array.

def add_field(a, descr):
    if a.dtype.fields is None:
        raise ValueError, "`A' must be a structured numpy array"
    b = numpy.empty(a.shape, dtype=a.dtype.descr + descr)
    for name in a.dtype.names:
        b[name] = a[name]
    return b

Although some people suggest using append_fields from numpy.lib.recfunctions, I have run into problems when the appended field will hold subarrays.

Using the Code Sample from the NumPyArrayToFeatureClass (arcpy.da) Help page (but dropping the TX spatial references):

import numpy

outFC = #Output FS location and name

# Create a numpy array with an id field, and a field with a tuple 
#  of x,y coordinates
array = numpy.array([(1, (471316.3835861763, 5000448.782036674)),
                     (2, (470402.49348005146, 5000049.216449278))],
                    numpy.dtype([('idfield',numpy.int32),('XY', '<f8', 2)]))

# Export the numpy array to a feature class using the XY field to
#  represent the output point feature
arcpy.da.NumPyArrayToFeatureClass(array, outFC, ['XY'])

yields a feature class with the following table:

numpyarraytofeatureclass_code_sample_table.PNG

Using the add_field function above to duplicate the 'XY' field:

import numpy

outFC = #Output FS location and name

# Create a numpy array with an id field, and a field with a tuple 
#  of x,y coordinates
array = numpy.array([(1, (471316.3835861763, 5000448.782036674)),
                     (2, (470402.49348005146, 5000049.216449278))],
                    numpy.dtype([('idfield',numpy.int32),('XY', '<f8', 2)]))

# Add new field to duplicate XY field so they show up as attributes
arr = add_field(array, [('XY1', '<f8', 2)])
arr['XY1'] = array['XY']

# Export the numpy array to a feature class using the XY field to
#  represent the output point feature
arcpy.da.NumPyArrayToFeatureClass(arr, outFC, ['XY'])

yields a feature class with the following table:

numpyarraytofeatureclass_code_sample_added_field_table.PNG

Unlike the Code Sample, I usually don't store the XY coordinates as a tuple in a numpy structured array because they end up getting stored as subarrays, which I find a bit more cumbersome to work with and not a requirement to use NumPyArrayToFeatureClass.

0 Kudos
XanderBakker
Esri Esteemed Contributor

You could after creating the shapefile, use the Add XY tool to add the coordinates:

arcpy.AddXY_management(in_features)

Some other tips:

  • Use syntax highlighting for your code to make it more readable. Curtis has a nice post on this: Posting Code blocks in the new GeoNet
  • When creating a spatial reference you don't need to do this:

WKID = 4326 # WGS-1984
sr = arcpy.SpatialReference()
sr.factoryCode = WKID
sr.create()

rather do this:

WKID = 4326 # WGS-1984
sr = arcpy.SpatialReference(WKID)
# or:
sr = arcpy.SpatialReference(4326) # WGS-1984

  • When you create the file path, I suppose you have a trailing slash at the end of the path. It is cleaner to do this:

import os
out_fc = os.path.join(strFilePath, strShapeFileName)

  • When assigning a boolean it is better to use a boolean:

 env.overwriteOutput = True # instead of  env.overwriteOutput = 1

Kind regards, Xander

DallasShearer
Deactivated User

Try printing the data from the numpy array before you use it for building the shapefile; verifying that the data is in fact in the numpy array before you use it to build the shapefile. Problem could possibly be how the datarray and dtype map out to one another.

print npyarr['LONGITUDE']

print npyarr['LATITUDE']

0 Kudos