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

4754
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
1 Solution

Accepted Solutions
JoshuaBixby
MVP Esteemed Contributor

Although not documented, you can point Layer directly to a data set.  Try the following for the execute block:

    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

View solution in original post

44 Replies
RebeccaStrauch__GISP
MVP Emeritus

Joseph, welcome to the Geonet Community forums.  First, don't get discouraged, but you should move this to the https://community.esri.com/community/developers/gis-developers/python?sr=search&searchId=83795ee7-e0...‌ , since the ArcGIS API for Python is actually a newer product, mainly used for administration portals and for doing some analysis, simple mapping etc. outside of ArcMap/Catalog/Pro.  You can move it using the pulldown under Actions in the upper right corner.  I would have done this for you, but I don't have those rights in this space.  By adding the @ and space name it actually gets tagged.  I'll also add https://community.esri.com/community/gis/mapping?sr=search&searchId=b9b071a9-f5ac-4fac-92ae-c17ef967...‌ 

Also, always good to post code using one of the options /blogs/dan_patterson/2016/08/14/script-formatting?sr=search&searchId=1753a87a-9033-4500-afb8-f4155c0...‌  That way, the pesky spaces etc of python don't cause issues and there are line numbers to help with feedback.

Also, tech support doesn't necessarily follow the forums.  It will be other users (and yes, their are serious developers that are active in the forums).  

Again, don't get discouraged on using the forums.  Very active these days.  

JoshuaBixby
MVP Esteemed Contributor

I haven't had a chance to test the code yet, but on first glance the following two lines caught my eye:

desc = arcpy.Describe(input_feature_class)
if desc.FIDSet:

Since feature classes don't support FIDSet, feature layers do, the code above should generate an AttributeError if passed a feature class.  Are you seeing an AttributeError or are you passing it a feature layer?

JosephArmbruster
New Contributor III

Joshua, the problem is not as trivial as an AttributeError, hence why I added the 'serious ESRI devs only 🙂

For clarification, the parameter type is a GPFeatureLayer but I access the parameter valueAsText and pass it into Describe.  Which is the correct ArcPythonic way of doing this.  FIDSet is a valid attribute in my test case.

0 Kudos
JamesCrandall
MVP Frequent Contributor

It looks like you are trying to get the count on the feature class, not what is loaded in the mxd document. 

feature_count = int(arcpy.GetCount_management(input_feature_class).getOutput(0)‍‍

This is working for a layer loaded in the TOC:

mxd = arcpy.mapping.MapDocument('CURRENT')
df = arcpy.mapping.ListDataFrames(mxd)[0]
lyr = arcpy.mapping.ListLayers(mxd, "SomeLayerInTOC", df)[0]
desc = arcpy.Describe(lyr)
feature_count = desc.FIDSet
print("Number of selected features: {}".format(len(feature_count.split(";"))))

XanderBakker
Esri Esteemed Contributor

I have given it a shot and noticed a few things, but did manage to get it to work (although I'm using 10.6). What I did was:

I have an mxd open with a layer in it:

I ran this code in the Python window of my ArcMap session:

import arcpy
import os
arcpy.env.overwriteOutput = True

path = r'C:\GeoNet\Selection\test.gdb\myLines' #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) # this already adds the layer to the data frame
move_layer = arcpy.mapping.ListLayers(mxd, new_layer_name, mxd.activeDataFrame)[0]
ref_layer = arcpy.mapping.ListLayers(mxd, "", mxd.activeDataFrame)[-1]
arcpy.mapping.MoveLayer(mxd.activeDataFrame, ref_layer, move_layer, "AFTER")

del move_layer
del ref_layer
del mxd

Notice that there are a few difference with the code you provided:

  • I have added the overwriteOutput = True on line 3 since the new_layer_name will already exist after the first run and throw an error
  • on line 8, when you create a feature layer, it is already added to ArcMap (at the top, which you don't want)
  • You have a line of code that not added the layer but the layer name, which was wrong
  • On line 9 I create a layer object from the layer added and on line 10 I get a reference to the last layer in the TOC
  • On line 11 these layers are used to move the added layer to the bottom

Now we have the layer at he bottom of the TOC:

Next step is to do something with the tool to investigate the selection. I created a simple tool and added this script:

def main():
    import arcpy

    # GPFeatureLayer
    feature_layer = arcpy.GetParameter(0)

    desc = arcpy.Describe(feature_layer)
    fid_set = desc.FIDSet
    if fid_set == '':
        lst_fid = []
    else:
        lst_fid = fid_set.split(';')
    if len(lst_fid) > 0:
        arcpy.AddMessage('selection made: {}'.format(len(lst_fid)))
        arcpy.AddMessage(lst_fid)
    else:
        arcpy.AddMessage('no selection made: {}'.format(len(lst_fid)))
        arcpy.AddMessage(lst_fid)

    feature_count = int(arcpy.GetCount_management(feature_layer).getOutput(0))
    arcpy.AddMessage('feature count: {}'.format(feature_count))

if __name__ == '__main__':
    main()

It only has a single parameter (Feature Layer). When I run the tool the first time (no selection made yet) something interesting is happening:

The added layer appears twice in the list. When I select the first element it will run and yield this:

Which was to be expected since no selection was made. 

I can make a selection:

And run the tool again, and this time only a single myLines is in the list:

It has a selection which is correctly detected both ways:

So apart from the fact that the layer appears twice in the list of feature layers, the tool seems to work and detect the selection.

JosephArmbruster
New Contributor III

So, a few things here..

1. "on line 8, when you create a feature layer, it is already added to ArcMap (at the top, which you don't want)"

MakeFeatureLayer_management does not necessarily add the layer to a dataframe...

2. "You have a line of code that not added the layer but the layer name, which was wrong"

It's not wrong, that's a valid use for MakeFeatureLayer_management... It creates a feature layer, which is not necessarily attached to a data frame... Oh, andI believe  the layer names passed to MakeFeatureLayer must be unique per-process.  Otherwise, not sure how you would delete it once it's no longer needed, unless you can obtain the generate layer as an output parameter...

2."So apart from the fact that the layer appears twice in the list of feature layers, the tool seems to work and detect the selection."

That's a reasonably unacceptable workaround for an obvious software problem 🙂

0 Kudos
XanderBakker
Esri Esteemed Contributor
MakeFeatureLayer_management does not necessarily add the layer to a dataframe...

It is the default setting in ArcMap. 

If you will share the tool to other users, you will need to account for that behavior or check if it was added or not.

It's not wrong, that's a valid use for MakeFeatureLayer_management.

Make me wonder why an error is produced in my case when using your exact code...

That's a reasonably unacceptable workaround for an obvious software problem 🙂

Contact support...

0 Kudos
XanderBakker
Esri Esteemed Contributor
MakeFeatureLayer_management does not necessarily add the layer to a dataframe...

It is the default setting in ArcMap. 

If you will share the tool to other users, you will need to account for that behavior or check if it was added or not.

It's not wrong, that's a valid use for MakeFeatureLayer_management.

Make me wonder why an error is produced in my case when using your exact code...

That's a reasonably unacceptable workaround for an obvious software problem 🙂

Contact support...

0 Kudos
JosephArmbruster
New Contributor III

You need to add the layer just like I did to experience the issue...

0 Kudos