Select to view content in your preferred language

Arcpy.mapping.AddLayer selection Funk (serious ESRI devs only)

5412
44
Jump to solution
02-05-2018 11:23 AM
JosephArmbruster
New Contributor III
Hey everyone,
It's been ages since i've had to resort to the forums, but the time has come...  This is issue is occurring with:
10.3.0.4322
AND
10.5.1.7333
Problem: When a layer is added to the TOC, just as you see in the snippet below, feature selections will no longer be respected (or at least detected) by geoprocessing tools.
Description: The symptom of the problem is that obtaining the feature selection count of a geoprocessing layer in a python toolbox is inconsistent.  I've pinned it down to some issue with the way Arc (or ArcPy) is handling layers by Name.  Here are some snippets:
# make this an absolute path to some feature class in a geodatabase, you only need a minimum of two features to reproduce the issue, i'm using polygons.

path = #path to your polygon feature class with at least two features in it.
mxd = arcpy.mapping.MapDocument('CURRENT')
new_layer_name = os.path.basename(path)
arcpy.MakeFeatureLayer_management(path, new_layer_name)
new_layer = arcpy.mapping.Layer(new_layer_name)
arcpy.mapping.AddLayer(mxd.activeDataFrame, new_layer_name, 'BOTTOM')
del new_layer
del mxd
Use the code above in a geoprocessing tool to add a layer to the map.

Now, use the code below in a separate geoprocessing tool, to report the number of features selected in the map.
desc = arcpy.Describe(input_feature_class)
if desc.FIDSet:
 messages.addMessage('selection made')
 # you'll never get here with the layer above!!
else:
 messages.addMessage('no selection made')
 # you'll always get here even with a selection 😞
# count will always be the entire feature class count, since no selection was registered
# to the layer....
feature_count = int(arcpy.GetCount_management(input_feature_class).getOutput(0)

Notes:
- If you use the code above to add the feature class to the map.  Remove it from the toc (right click, remove) and add it using arc catalog (drag-drop), the feature selection will STILL not work.  Hence why I suggest it has something to do with the internal name resolution.
- If you start a new ArcMap instance, add the layer by drag-dropping it from Arc Catalog, the selection WILL work.  If you remove this layer and add it using the code above, all subsequent selections will NOT be respected.

I look forward to hearing from ESRI support.
Let me know if you have any questions,
Joseph Armbruster
0Lat Inc, Orlando Florida.
0 Kudos
44 Replies
JosephArmbruster
New Contributor III

Everyone, i'm on travel and will not be back at it until this Monday.  I'll reply with my final resolution then.  Please stand by for more.

0 Kudos
LukeWebb
Occasional Contributor III

Im interested in what you are trying to achieve with the code here:

new_layer = arcpy.mapping.Layer(new_layer_name)‍‍‍‍‍‍‍‍

As you are simply passing it a string, no paths to any data or anything.

dataset_to_process = r'FULL_PATH_TO_A_FEATURE_CLASS_IN_A_GEODATABASE'  
#e.g.  C:\temp\a.gdb\layername
        
new_layer_name = os.path.basename(dataset_to_process)     
#e.g.    layername     ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The layer that did get added to your map, came from MakeFeatureLayer_management due to the default arcmap setting.

The second bunch of code (arcpy.Mapping.Addlayer etc) should (and does on my pc) have crashed as the layer we make in the above fashion cannot be correct.

However I feel it may somehow be making a ghost layer, that has no selections applied for obvious reasons. (e.g. a bug in ESRI, that wont manifest if you use the software as intended)

0 Kudos
JosephArmbruster
New Contributor III

MakeFeatureLayer_management does not necessarily add the layer to a data frame.  If you're running tools headless (without the ArcMap frontend,) there's no data frame for it to be added to, necessarily.  You can use it to create layers in a script that are never seen by the user, to do all sorts of things, perform selections, etc... It's interesting to me that the add layer function worked (correctly or not) 'by name' vs... 'by layer', which isn't documented and should not really work at all...

I'm still away from my machine, will get back to it shortly...

0 Kudos
JosephArmbruster
New Contributor III

I'm back to it and have been testing the recommendation from @bixb0012 above.  I received a response from ESRI, but I didn't really like mangling the output parameters.  I preferred the more direct approach of adding the layers explicitly with the mapping.Layer call.  Removing the AddFatureLayer_management call and adding the dataset directly to the Layer call appears to work.

def execute(self, parameters, messages):

        dataset_to_process = # path to feature class

        mxd = arcpy.mapping.MapDocument('CURRENT')
        lyr = arcpy.mapping.Layer(dataset_to_process)
        arcpy.mapping.AddLayer(mxd.activeDataFrame, lyr, 'BOTTOM')
        del lyr
        del mxd
        arcpy.RefreshTOC()

        return

If I experience any issues with his approach, i'll post back... otherwise, i'll consider his answer correct.

Cheers!

JoshuaBixby
MVP Esteemed Contributor

Just an FYI.  The undocumented behavior works for as long as I can remember, back to 9.x days.  That said, I learned from conversations with a Product Lead that the behavior wasn't planned, i.e., it was sort of an accident it works directly with data sets.  Instead of "fixing" it in ArcMap, which might very well cause existing code to break, they opted to address it in ArcGIS Pro.

You will notice in ArcGIS Pro that Layer has be renamed to LayerFile and the documentation now explicitly states it only works on layer files:

Summary

References a layer file (.lyr or .lyrx) stored on disk.

Attempting to pass a data set to LayerFile in Pro generates a ValueError.