SHAPE from Cursor doesn't save correctly in List of Dictionaries

1246
6
07-07-2011 05:32 AM
ChristopherFricke1
New Contributor
I am having an issue with this bit of python. 

Basically I open up a cursor to loop through a feature class.  At each row, I take every field and put the values in a dictionary.  I then append this to a list.  I am specifically interested in ObjectID and SHAPE

Next I unpack the list of dictionaries and print the ObjectID and SHAPE.

For some reason the SHAPE component isn???t saved properly.  But the ObjectID is.  I think this is a  bug with ArcPy, but it could just as likely be a bug with my code.


I get the following output:

1 - -8359910.19268255 4842313.47802997 NaN NaN
2 - -8353926.32475581 4846897.25034694 NaN NaN
3 - -8359087.54168308 4842848.29488585 NaN NaN

************

1 - -8359087.54168308 4842848.29488585 NaN NaN
2 - -8359087.54168308 4842848.29488585 NaN NaN
3 - -8359087.54168308 4842848.29488585 NaN NaN




import arcpy

fc = r'C:\Users\cfricke.GISINC\Documents\BOMBED\Test.gdb\Stores'

cursor = arcpy.SearchCursor(fc)
fields = arcpy.ListFields(fc)
geo = arcpy.Describe(fc).ShapeFieldName
idField = arcpy.Describe(fc).OIDFieldName

###
# Part A
# Output Cursor into List of Dictionaries
# Print ObjectID and Shape at each iteration
###
fcList = []
for row in cursor:
    fcDict = {}
    for field in fields:    
        fcDict[field.name] = row.getValue(field.name)
        if field.name == geo:
            print "%s - %s" % (row.getValue(idField), row.getValue(field.name).getPart())
    fcList.append(fcDict)
    del fcDict

print ""
print "************"
print ""

###
# Part B
# Loop through list of dictionary, print objectID and shape
###
for x in fcList:
    print "%s - %s" % (x[idField],x[geo].getPart())

del fcList
Tags (2)
0 Kudos
6 Replies
StacyRendall1
Occasional Contributor III
Hi Christoph,

I don't know much about this stuff, but it would appear that the SHAPE info is being stored as an arcobjects object (i.e. not a Python data type). Python asks Arc for the object, but it appears that only the most recent object is returned - this is why it later gets stuck on the last SHAPE info it read.

If you convert the SHAPE info to a string when you read it, shown below, the output looks correct, but it isn't particularly useful if you want to do something else with the point at a later stage...

import arcpy

fc = r'C:\Users\cfricke.GISINC\Documents\BOMBED\Test.gdb\Stores'

cursor = arcpy.SearchCursor(fc)
fields = arcpy.ListFields(fc)
geo = arcpy.Describe(fc).ShapeFieldName
idField = arcpy.Describe(fc).OIDFieldName

###
# Part A
# Output Cursor into List of Dictionaries
# Print ObjectID and Shape at each iteration
###
fcList = []
for row in cursor:
 fcDict = {}
 for field in fields: 
  if field.name == geo:
   fcDict[field.name] = str((row.getValue(field.name)).getPart())
   print "%s - %s" % (row.getValue(idField), (row.getValue(field.name)).getPart())
  else:
   fcDict[field.name] = row.getValue(field.name)
 fcList.append(fcDict)
 del fcDict

print ""
print "************"
print ""

# ###
# # Part B
# # Loop through list of dictionary, print objectID and shape
# ###
for x in fcList: # for every feature
 print "%s - %s" % (x[idField], x[geo])


If you want the SHAPE data as numbers (more useful if you wanted to do some processing, etc., at a later stage), you could do something like this (more complex stuff would be required for lines, polygons, etc.):

import arcpy

fc = r'C:\Users\cfricke.GISINC\Documents\BOMBED\Test.gdb\Stores'

cursor = arcpy.SearchCursor(fc)
fields = arcpy.ListFields(fc)
geo = arcpy.Describe(fc).ShapeFieldName
idField = arcpy.Describe(fc).OIDFieldName

###
# Part A
# Output Cursor into List of Dictionaries
# Print ObjectID and Shape at each iteration
###
fcList = []
for row in cursor:
 fcDict = {}
 for field in fields: 
  if field.name == geo:
   fcDict[field.name] = [row.getValue(field.name).firstPoint.X, row.getValue(field.name).firstPoint.Y, row.getValue(field.name).firstPoint.Z, row.getValue(field.name).firstPoint.M]# add the geo data as a list
   print "%s - %s" % (row.getValue(idField), (row.getValue(field.name)).getPart())
  else:
   fcDict[field.name] = row.getValue(field.name)
 fcList.append(fcDict)
 del fcDict

print ""
print "************"
print ""

# ###
# # Part B
# # Loop through list of dictionary, print objectID and shape
# ###
for x in fcList: # for every feature
 print "%s - %s" % (x[idField], x[geo])


You can now use the X, Y, Z (=None), and M (=None) data after you use indexes to the list to fetch them... Hope this is helpful!
0 Kudos
ChristopherFricke1
New Contributor
Thanks.  I was suspecting that.
0 Kudos
ChrisSnyder
Regular Contributor III
Read this:
http://forums.arcgis.com/threads/17956-Using-centroid-geometry-to-get-values-of-intersecting-feature...
and the posts below it.

Basically, we came to the same conclusion: You can't directly store/use the geometry object in a Python dictionary.
0 Kudos
RichardFairhurst
MVP Honored Contributor

Chris:

This code is all with the old style cursors and direct reading of the shape field into the dictionary.  Did you ever try using a da cursor and a filtered field list that used the "SHAPE@" field value to populate the dictionary?  Did it cause the same corruption problems?

The use of the dictionary is sooo much faster than an embedded cursor pair or repeated use of select by attribute queries for feature matching when there is a matching attribute key.  If the Shape geometry could transfer or be read from the dictionary it would be so much better.

If using a dictionary is still not possible, have you come up with any alternative processing algorithm that avoids the exponential loop growth of an embedded cursor pair routine or the slow processing of repeatedly doing a Search by Attribute for one feature match at a time?  For example, is it possible that loading the source/read-only FC into an inmemory FC could speed up either the embedded cursors or repeated search by attribute queries.rather than doing these routines directly against the on-disk FC?

0 Kudos
NeilAyres
MVP Alum

Richard,

reading fc records of geometry and attributes into a dictionary for further processing works a treat (at the mo on v10.2).

Used it often recently to do geometry comparisons (intersect etc).

Cheers,

Neil

0 Kudos
ChrisSnyder
Regular Contributor III

Hi Richard,

Well I guess it seems to work well now. Here's a somewhat recent example: https://community.esri.com/message/362783#362783

In that message I tried to goad someone from ESRI to give an explanation and/or assurance everything was a-okay now, but no takers.

0 Kudos