Bug report on arcpy.Describe

3510
11
06-09-2015 08:34 AM
ThomasBecker1
Occasional Contributor II

Since ESRI put the customer number and phone number as protection from customers in I cannot find any other way...

Using ArcGIS in version 10.3 and retrieving the count for selected features in a feature class utilizing

arcpy.Describe('my_feature_class').fidset.split(';')

, the minimum number delivered back is 1.

To illustrate the problem a bit...

2.pngFigure 1: Two polygon feature classes, where the circle is a buffer created around a point. The question at hand is, if there is any polygon from the other feature class intersecting with the buffer. As visible in the image, there is no intersecting feature.

3.pngFigure 2: The attempt to find intersecting features, using the SelectLayerByLocation function. No feature is selected, but when requesting the number of objects through the Describe function, the length of the list is one and not zero! The length of the list is not correct since the Describe function delivers an empty string back in case there is no intersecting feature.

1.pngFigure 3: Another buffer, this time intersecting with the other polygon layer. Clearly, the two polygon layer have intersecting features.

4.pngFigure 4: Again, the SelectLayerByLocation function used to select intersecting features, and the Describe function utilized to retrieve the number of intersecting features. While the length of the list is the same, the list item itself is holding this time the correct FID of the intersecting feature.

5.png

Not really nice, when you want to exclude buffers that do not have any intersecting features in another feature class, and/or want to work with buffers that have only a single object intersecting.

Finally: The system to submit bug reports is flawed. Why does not have any user the possibility to submit bug reports, no matter if you have a customer number at hand or not? My technical support is not available, due to working hours, and I will not invest the time to find out the customer number and the phone number connected to the account to contact ESRI via a 'Support Request Form'.

Just my fifty cents,

Thomas

Tags (2)
0 Kudos
11 Replies
DuncanHornby
MVP Frequent Contributor

Thomas,

Agree ESRI support can be frustrating especially if you want to fire off a potential bug in the software.

But for your problem here is a simple work around, don't try to get the length of the list when you want to identify if your layer had a selection. That's obviously a weird bug as a list with an empty string is an odd thing to return. I would simply do this:

if len(arcpy.Describe("Field Sites").fidset) > 0:

    print "You have a selection"

else:

    print "No features selected"

Duncan

0 Kudos
ThomasBecker1
Occasional Contributor II

Hi Duncan,

the way you point out was my first attempt to get things done. Problem when doing it this way is that you still get all the buffers that do not have a match. The empty string will tell you you have a match of '1', while in fact there is no match. Moving up, saying ' > 1' will make you miss all the buffers that have exactly one polygon intersecting the buffer.

In the end my workaround is:

lst = arcpy.Describe('my_layer').fidset

if len(lst) > 0:

That will give you the number of characters in the list back, but it will also give you a clear zero in case there is a [u''].

I have a bit more than 10.000 points to run for eight different datasets and five different buffer sizes. Meaning I have to be able to trust the returned value. 😉

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

What you are running into is a Python issue/idiosyncrasy, not really an ArcPy issue.  An empty string doesn't say you have a match of '1', an empty string is saying there are no matched because the fidset is empty.  The reason your length check is returning 1 is due to how the Python string splitting method works, specifically related to separators.

5.6.1. String Methods

....

str.split([sep[, maxsplit]])
    ....

If sep is given, consecutive delimiters are not grouped together and are deemed to delimit empty strings (for example, '1,,2'.split(',') returns ['1', '', '2']). The sep argument may consist of multiple characters (for example, '1<>2<>3'.split('<>') returns ['1', '2', '3']). Splitting an empty string with a specified separator returns [''].

If sep is not specified or is None, a different splitting algorithm is applied: runs of consecutive whitespace are regarded as a single separator, and the result will contain no empty strings at the start or end if the string has leading or trailing whitespace. Consequently, splitting an empty string or a string consisting of just whitespace with a None separator returns [].

Looking at a few examples:

>>> fidset_empty = ''

>>> fidset_empty.split(';')

['']

>>> fidset_one = '1'

>>> fidset_one.split(';')

['1']

>>> fidset_two = '1; 2'

>>> fidset_two.split(';')

['1', ' 2']

The length of lines 03 and 06 are both 1 because a separator was explicitly passed to the split method so an empty string returned a list with an empty string.  If you can live with the extra semicolon being attached to all but the last FID, then passing no separator to split will yield an empty list with a length of zero.

>>> fidset_empty.split()

[]

>>> len(fidset_empty.split())

0

With your workaround code, you are using a variable 'lst'.  Although 'lst' could be anything, most people reading your code would assume it is a list, but it is actually a string because fidset returns a string and not a list.

0 Kudos
ThomasBecker1
Occasional Contributor II

Concerning the last of your points: Yes, lst can be anything, and yes most people will take it for a list...

Concerning your suggestion of splitting without a separator specified is actually really helpful!

Another way of handling the issue could be to go with Python and take the empty string for what it is: False.

lst = u''

if not lst: #or what ever variable you want to use

will return True.

Thinking again about the suggested GetCount - its only a crutch. If nothing is selected the function will return the total amount of rows in a dataset. Hence I think fidset is the more elegant way and in the context of what I need it's the more relevant.

Long story short - To exclude buffers that do not intersect with any other feature, and therefore do not return selected features in a feature class my way is:

if arcpy.Describe('polygon_class').fidset:

     # code to be executed in case there are features selected

else:

     # code to be executed in case there are NO features selected

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

I think you want Get Count.  Get Count is designed to work on views, layers, and similar such.  Describe is more focused on data sources.

The reason you are seeing 1 in your first example is because the Python string split method is returning your empty string back to you in a list.  A list with a single empty string in it has a length of 1.

You are not handling the no selected features situation correctly.  Before you run split, check to see if fidset returns an empty string, which indicates no selected features.  If you are only interested in counts and not FIDs of selected features, I think Get Count works well.

0 Kudos
ThomasBecker1
Occasional Contributor II

Joshua,

I slightly disagree... I do not have the data at hand at the moment, but give it a shot with some of your data.

In case of no intersecting feature arcpy.Describe('your_dataset').fidset will return [u'']. Hence, the empty string isn't a product of the split-function.

With respect to the use of fidset, the page is clearly defining the property as 'A semicolon-delimited string of selected feature IDs (record numbers).' That is exactly what I want and need. You are of course correct that GetCount will return only the number of selected features if there is any selected. However, that doesn't change that the returned value for the fidset property is wrong.

Therefore, it is not me who is handling the result the wrong way. The result is wrong in the first place. Check the property without the split. If there is no feature selected then the list is supposed to be empty, technical speaking '[]' and not '[u'']'.

0 Kudos
JoshuaBixby
MVP Esteemed Contributor

The FIDSet property doesn't return a Python list, it returns a Python string that represents a list of FIDs.  Since the property is string-based, there is nothing else besides an empty string (u'')that can be returned when no records are selected.  It is the behavior of the Python string splitting function that is returning a list with an empty string instead of an empty list, but that is a Python issue and not an ArcPy issue.  If arcpy.Describe('your_dataset').fidset is returning a list, trying to split it will fail either by an AttributeError or TypeError depending on your syntax.

0 Kudos
SusanJones
Occasional Contributor II

Hi

Will arcpy.GetCount_management("MP_1996_P") solve the issue ?

Susan

0 Kudos
ThomasBecker1
Occasional Contributor II

Hi Susan,

It most likely will. The point is, that the returned value of the fidset property isn't correct and GetCount was simply not what I was thinking of. 🙂

0 Kudos