Did MakeFeatureLayer_management change from 10.1 to 10.2?

6089
19
09-30-2015 06:28 PM
GeorgeRiner
New Contributor III

I have Python code that creates a file geodatabase on the user's local data directory, creates some features in the .gdb (involves copying features, merging, intersecting, etc.) and results in a feature class in that local .gdb that I then want to add to the current map document, to show the results of all the Python/arcpy processing for the user that ran the tool.

The issue is that in 10.2 arcpy.MakeFeatureLayer_management does not add my final feature class to the current map document's TOC, So I use arcpy.mapping.Layer to make a layer of my final product and then use arcpy.mapping.AddLayer to add the layer to the current map document. Works great.

But then the tool gets run on a different user's machine that's running ArcMap 10.1 and MakeFeatureLayer_management barks with an error '000733' - output layer is same as input layer. So I remove the arcpy.mapping code and just let MakeFeatureLayer_management work with the single parameter and now my results get added to the current map's TOC!

(this is all 32-bit python/geoprocessing)

The on-line documentation for 10.1 and 10.2 for MakeFeatureLayer_management don't mention any difference in behavior concerning whether the dataset's layer gets added to the current map document.

0 Kudos
19 Replies
curtvprice
MVP Esteemed Contributor

You can return a feature class, a feature layer, or a feature set. Any of these types will add a layer to the map. Unless you are planning on set this up a a web service, feature class is the best to use.

0 Kudos
curtvprice
MVP Esteemed Contributor

I think the most straightforward way to add the results to the map is to use a derived parameter. For example:

# script tool
import os
import arcpy
input = arcpy.GetParameterAsText(0)
in_path = arcpy.Describe(input).catalogPath
out_path = os.path.join(os.path.dirname(in_path), "output")
arcpy.Copy_management(in_path, out_path)
arcpy.SetParameterAsText(1, out_path)

In the script tool properties set up the first parameter as "Input", "Feature Layer" and the second parameter as "Derived", "Feature Class". This has the additional benefit of having it pop out of your script tool when  you drag it into ModelBuilder. This ​should work whether you have background processing turned on or not. (Before 10.1 SP 1, there was no such thing as background processing.)

Understanding script tool parameters—Help | ArcGIS for Desktop

GeorgeRiner
New Contributor III

Let me say more about this...

I've reduced the code down to show the basic process, without making it too simplified.

In this reduced example code, I've ripped out all the code that uses a couple other Python modules that are in the actual production code: pymssql (to pull data from our SQL server database), and openpyxl (to update an excel spreadsheet with more data about the results of the code running). Also gutted out is code that detects if data from a previous run of the tool exists, in which case it deletes it before continuing on to to the actual processing.

Herewith:

import arcpy
import os
import getpass


# save the current workspace
save_workspace = arcpy.env.workspace


# get the current user's login id
run_user = getpass.getuser()


# get 3 parameter values
ex_district = int(arcpy.GetParameterAsText(0))
ex_year = int(arcpy.GetParameterAsText(1))
ex_num = int(arcpy.GetParameterAsText(2))


# this is where the 'raw' data is coming from
data_source = r"N:\gis-files\merged.gdb\raw"


# this where the prepared data is going to
destination_gdb_directory = r"N:\shared\George"
destination_gdb_name = "ex_gdb.gdb"
arcpy.CreateFileGDB_management(destination_gdb_directory,destination_gdb_name)


# set the workspace to this destination GDB
arcpy.env.workspace = os.path.join(destination_gdb_directory,destination_gdb_name)


# create a new feature class in the destination GDB
estination_feature_class = "example_results"
destination_feature_template = r"MAIN\Reports\Reports (polygons)"
arcpy.CreateFeatureclass_management(arcpy.env.workspace,destination_feature_class,"POLYGON",destination_feature_template,"SAME_AS_TEMPLATE","SAME_AS_TEMPLATE",destination_feature_template)


# create some kind of 'layer' that is a selection of the 'raw' data
ex_where = "(REGION={0} AND YEAR={1} AND NUM={2})".format(ex_district,ex_year,ex_num)
ex_data_select = "example_data_select"
arcpy.MakeFeatureLayer_management(data_source,ex_data_select,ex_where)


# copy the selected features out of the 'raw' data
ex_data_copied = "example_data_copied"
arcpy.CopyFeatures_management(ex_data_select,ex_data_copied)


# dissolve them into 1 feature
ex_data_dissolved = "example_data_dissolved"
arcpy.Dissolve_management(ex_data_copied,ex_data_dissolved,"","","MULTI_PART")


# cut that feature up by county boundary
ex_data_intersected = "example_data_intersected"
ex_intersect_inputs = [ex_data_dissolved, 'Basemap\\County outlines']
arcpy.Intersect_analysis(ex_intersect_inputs,ex_data_intersected,"ALL", "", "INPUT")


# add features to the prepared data with our attributes
from_shape_field = arcpy.Describe(ex_data_intersected).ShapeFieldName
to_shape_field = arcpy.Describe(destination_feature_class).ShapeFieldName


copy_from = arcpy.SearchCursor(ex_data_intersected)
insert_to = arcpy.InsertCursor(destination_feature_class)


for from_row in copy_from:
  new_row = insert_to.newRow() # create empty record
  new_row.setValue(to_shape_field,from_row.getValue(from_shape_field)) # copy geometry
  new_row.setValue('DocNo',ex_num) # put in  source document number
  new_row.setValue('OtherID',from_row.getValue('NAME')) # copy county name
  new_row.setValue('DigBy',getpass.getuser()) # put in user name
  insert_to.insertRow(new_row) # add feature to final destination
  del new_row
del copy_from
del insert_to


# load the destination_feature_class into the user's map TOC
new_map_layer = "Your Results"
arcpy.MakeFeatureLayer_management(destination_feature_class,new_map_layer)
this_mxd = arcpy.mapping.MapDocument("CURRENT")
this_frame = arcpy.mapping.ListDataFrames(this_mxd)[0]
this_layer = arcpy.mapping.Layer(new_map_layer)
arcpy.mapping.AddLayer(this_frame,this_layer,"TOP")


# restore the prior workspace
arcpy.env.workspace = save_workspace

(let me know if the Python code snippet didn't paste in correctly above)

This is run as a script tool in a 'plain' toolbox (not a 'Python toolbox'). On my 10.2 installation it works like a charm. The only layer that gets added to my map is the one at the end and it shows up at the top of the TOC as 'Your Results'. And it contains the correct data. Yay!

Now... for the interesting part ...

I log in, as me, on a different machine that's installed with 10.1 and I run this tool and it also works as expected. Grnpph. So... either:

1) in simplifying the code for example/discussion purposes I inadvertently fixed the problem or removed problem-causing code;

or

2) something about the profile of the usual user is causing it to bomb out. The usual user of this tool has left for the day and I can't log in as them to try it out under their login today. I'll try it out with them the next time they're in and available.

0 Kudos
curtvprice
MVP Esteemed Contributor

George, I still don't see the need for arcpy.mapping here. Could you return a feature class as a derived parameter?   As far as I can tell you are losing no functionality doing it that way and gaining some: a side benefit to using a derived parameter is that the tool will run nicely in a ModelBuilder chain, ArcCatalog, etc.

So what I"m suggesting is replacing this:

# load the destination_feature_class into the user's map TOC  
new_map_layer = "Your Results"  
arcpy.MakeFeatureLayer_management(destination_feature_class,new_map_layer)  
this_mxd = arcpy.mapping.MapDocument("CURRENT")  
this_frame = arcpy.mapping.ListDataFrames(this_mxd)[0]  
this_layer = arcpy.mapping.Layer(new_map_layer)  
arcpy.mapping.AddLayer(this_frame,this_layer,"TOP")  
  
  
# restore the prior workspace  
arcpy.env.workspace = save_workspace

with this, and add a fourth parameter ("Your results", Derived, type Feature Class) to your toolbox parameter list. Another nifty thing you can do is apply a layer file with symbology that you want as part of the derived parameter properties.

arcpy.SetParameterAsText(3, destination_feature_class)

BTW, environments in script tools are local so there is no need to restore the workspace at the end of the tool.

0 Kudos
GeorgeRiner
New Contributor III

Ok.  2 things...

1) I've been able to try out the example code (without Curtis' suggestion implemented) on the user's 10.1 station, logged in as them. It crashes on the MakeFeatureLayer_management at the end (line 85). So, whatever I'm stumbling across seems to be affected by the user profile, not the version of ArcGIS.

2) I switched over the code to Curtis' suggestion and it works as advertised. But the name of the layer shows up in the TOC as "example_results", not the name I want it to have (e.g. "Your Results") - which would be based on the user's inputs. I suppose I can work around this by making the name of the destination_feature_class to be name of the layer as I want it to appear in the TOC. I don't understand fully what is intended by the semantic: "(Your results", Derived, type Feature Class)". Here is how I setup the 4th parameter in the tool's properties box:

testing_1 Properties.tiff

As for environments being local - I confess I find the issues of namespaces and execution scoping to be a snake pit, so I just play it safe and save and restore values.

0 Kudos
DanPatterson_Retired
MVP Emeritus

line 35​ - missing the d in destination_feature_class

could just be a copy-paste issue and probably isn't relevant

0 Kudos
GeorgeRiner
New Contributor III

You are correct. It is a copy/paste issue. The widget for pasting in python code doesn't seem to work smoothly for 93 lines of code. I inadvertently deleted the 'd'.  The 'd' is there in the code on my machine.

0 Kudos
DanPatterson_Retired
MVP Emeritus

resolved with the login differences?

0 Kudos
GeorgeRiner
New Contributor III

Curtis' suggestion worked. I don't have the time to dig out the differences in the 2 user profiles to see what could cause the different outcomes.

0 Kudos
curtvprice
MVP Esteemed Contributor

> I don't understand fully what is intended by the semantic: "(Your results", Derived, type Feature Class)"

I meant name the variable "Your Results", with direction derived, and type Feature Class. I think you did it right.

0 Kudos