I have a python tool that will take a point feature class and does some magic and returns a polygon feature class (it works out areas where the points are clustered, adds fields, yadda yadda yadda). It runs great, does what I want it to do.
I need to turn that into a geoprocessing service that a user can run from arcmap and returns the polygon features as a layer to arcmap. How do I do that? I am able to run the tool and share the result as a service, but the service returns an empty result.
I think I'm just not able to follow the documentation on how to return a feature set to the user. Do I need to start a feature service using the results? If so, every time a user runs the tool does it start a new service? What parameters in python and on the service creation wizard do I need to set to enable this?
Thanks in advance...
-Brendan
Solved! Go to Solution.
Hi Brendan,
You don't need to start a new service with each result. The key is to make sure that your output is passed properly to the tool and that is has the right data type. Here are some pointers to start with and/or double check.
By the end of your script when you end up with your polygon feature class (say out_fc), make sure you use arcpy.SetParameter to make ArcGIS aware that out_fc is a result of your tool.
When you are adding the script to a toolbox so you can use it in ArcMap, make sure you set the parameter direction to "Output" and type to "FeatureClass".
After that, run the tool. Does the result get added to the map? It is a good sign if it does. Publish the geoprocessing result as a service. Then connect to the server and run the tool from the server. Does the result get added to the map?
Note that depending on your settings, geoprocessing results may not add to the map automatically so it is more reliable to check the content of the result object in Geoprocessing Results window. Often it helps me if I add in some messages with arcpy.AddMessage while debugging tools.
Here is a "skeleton" of a basic script that can be added to ArcGIS as a script tool.
import arcpy def main(in_points, out_fc): """Main function that does the magic""" out_fc = arcpy.analysis.Buffer(in_points, out_fc, 100).getOutput(0) return out_fc if __name__ == "__main__": in_points = arcpy.GetParameter(0) out_fc = arcpy.GetParameter(1) result = main(in_points, out_fc) arcpy.SetParameter(1, result)
Let us know how you get on.
Filip.
Hi Brendan,
You don't need to start a new service with each result. The key is to make sure that your output is passed properly to the tool and that is has the right data type. Here are some pointers to start with and/or double check.
By the end of your script when you end up with your polygon feature class (say out_fc), make sure you use arcpy.SetParameter to make ArcGIS aware that out_fc is a result of your tool.
When you are adding the script to a toolbox so you can use it in ArcMap, make sure you set the parameter direction to "Output" and type to "FeatureClass".
After that, run the tool. Does the result get added to the map? It is a good sign if it does. Publish the geoprocessing result as a service. Then connect to the server and run the tool from the server. Does the result get added to the map?
Note that depending on your settings, geoprocessing results may not add to the map automatically so it is more reliable to check the content of the result object in Geoprocessing Results window. Often it helps me if I add in some messages with arcpy.AddMessage while debugging tools.
Here is a "skeleton" of a basic script that can be added to ArcGIS as a script tool.
import arcpy def main(in_points, out_fc): """Main function that does the magic""" out_fc = arcpy.analysis.Buffer(in_points, out_fc, 100).getOutput(0) return out_fc if __name__ == "__main__": in_points = arcpy.GetParameter(0) out_fc = arcpy.GetParameter(1) result = main(in_points, out_fc) arcpy.SetParameter(1, result)
Let us know how you get on.
Filip.
Thank you very much for the response. One question: In the tool settings, if I set the out_fc parameter direction to 'Output', can I use the GetParameter method to get it? I thought it was one or the other.
Hi Brendad,
Yes, parameters with direction set to "output" can be accessed with both GetParameter and SetParameter methods (and their "AsText" variants).
It is a bit contra-intuitive at first but it does make sense. In the case of FeatureClasses for example, you use GetParameter at the beginning of the script to obtain the value defined by the user, which would be a path where the output feature class should be stored, and then you use SetParameter in the end to actually set the output value for that parameter.
Filip,
Filip,
Thanks for your help. I've got the service running now. Some additional pointers in case someone else has this question:
The parameters for the output feature class: Type > Required, Direction > Output. And DO NOT check the checkbox for 'View result as a service.' I think I had that checked from an earlier version and didn't catch it.
Thanks again. Your help was invaluable.
-Brendan
Filip,
Do you have any experience dealing with in_memory data? I have created a model and the last tool in the model is Make Route event Layer. the problem is the point file that I create earlier in the model gets stored in the GPInMemoryworkspace so the tool fails. Any idea how to access this point layer so I can create my line segment?
Thanks,
Terry
Hi Terry,
In-memory workspaces have certain limitations but I cannot see from your description why and how exactly is your model failing. Can you provide more details about what you are trying to do? Maybe a diagram of your model would help.
Also, does your question relate to what Brendan asked in the first place? Are you trying to publish your model as a service? If not, it might also be best to create a new thread for your question. Just mention @FIlip_Kral in the text of your question and I'll get a notification.
Filip.
Here is a view of the model. Yes I want to publish it as a service to use in WAB. I was trying to find someone with knowledge about GP and python. Here is the scenario, I created a model with the Make Route Event layer as the last tool and I want to create a segment. The points table has a route and a from and to offset for the MDTGISroute_LRM_DC to to locate the segment. The problem is the points table is in the GPInMemoryWorkspace so the tool does not see it. I tried to export the model to Python and add it as a tool but it hangs on the Locate Features Along Routes tool because my type of out_event_properties do not match the type of in_features. Which is odd as the model runs just fine.
Hmm... not sure where the problem is. There are a few things I'd have to try step by step but here are some suggestions:
Models exported to Python often need quite a bit of work to tidy them up so don't expect them to run straight away.
Filip.
Yeah I have been tinkering with the python script that was exported. Not really sure I understand how it makes the variables.. I set the output_event properties and now I can get it to run to the Make table view tool. the problem when I set them to "RID POINT MEAS" it actually changes my first_point and end_point tables so that the make table view no longer see it. This is what the python looks like.
Runtime error Traceback (most recent call last): File "<string>", line 68, in <module> File "E:\MDTAPPS\Desktop10.2\arcpy\arcpy\management.py", line 6514, in MakeTableView raise e ExecuteError: ERROR 000229: Cannot open E:\MDTAPPS\interactive\interactive.mdb\end_point Failed to execute (MakeTableView).
# -*- coding: utf-8 -*- # --------------------------------------------------------------------------- # new_seg1.py # Created on: 2015-10-28 15:17:56.00000 # (generated by ArcGIS/ModelBuilder) # Usage: new_seg1 <first_point> <end_point> <segment> # Description: # --------------------------------------------------------------------------- # Import arcpy module import arcpy arcpy.env.overwriteOutput = True # Load required toolboxes arcpy.ImportToolbox("E:/MDTAPPS/interactive/refmseg.tbx") # Script arguments first_point = arcpy.GetParameterAsText(0) if first_point == '#' or not first_point: first_point = "E:\\MDTAPPS\\interactive\\interactive.mdb\\first_point" # provide a default value if unspecified end_point = arcpy.GetParameterAsText(1) if end_point == '#' or not end_point: end_point = "E:\\MDTAPPS\\interactive\\interactive.mdb\\end_point" # provide a default value if unspecified segment = arcpy.GetParameterAsText(2) if segment == '#' or not segment: segment = "segment" # provide a default value if unspecified # Local variables: first_point__2_ = first_point beg_point = first_point__2_ first_pt_loc = beg_point temp = first_pt_loc points = temp Output_Event_Table_Properties = "RID POINT MEAS" end_point__3_ = end_point end_pt = end_point__3_ end_pt_loc = end_point__3_ end_pt_loc_Vw = end_pt_loc Output_Event_Table_Properties__2_ = "RID POINT MEAS" MDTGIS_ROUTES_LRM_RM = "MDTGIS.ROUTES_LRM_RM" MDTGIS_ROUTES_LRM_DC_MI = "MDTGIS.ROUTES_LRM_DC_MI" MDTGIS_ROUTES_LRM_DC_MI__2_ = "MDTGIS.ROUTES_LRM_DC_MI" interactive_mdb = "E:\\MDTAPPS\\interactive\\interactive.mdb" MDTGIS_ROUTES_LRM_DC = "MDTGIS_ROUTES_LRM_DC" # Process: Calculate Field arcpy.CalculateField_management(first_point, "Corridor", "str(!Corridor!) + \"_\" + str(!RM!)", "PYTHON_9.3", "") # Process: Calculate Field (2) arcpy.CalculateField_management(end_point, "Corridor", "str(!Corridor!) + \"_\" + str(!RM!)", "PYTHON_9.3", "") # Process: Make Route Event Layer arcpy.MakeRouteEventLayer_lr(MDTGIS_ROUTES_LRM_RM, "ROUTE_ID", first_point__2_, "Corridor POINT beg_offset", beg_point, "", "ERROR_FIELD", "NO_ANGLE_FIELD", "NORMAL", "ANGLE", "LEFT", "POINT") # Process: Make Route Event Layer (2) arcpy.MakeRouteEventLayer_lr(MDTGIS_ROUTES_LRM_RM, "ROUTE_ID", end_point__3_, "Corridor POINT end_offset", end_pt, "", "ERROR_FIELD", "NO_ANGLE_FIELD", "NORMAL", "ANGLE", "LEFT", "POINT") # Process: Locate Features Along Routes arcpy.LocateFeaturesAlongRoutes_lr(beg_point, MDTGIS_ROUTES_LRM_DC_MI, "CORRIDOR", "0 Meters", first_pt_loc, Output_Event_Table_Properties, "ALL", "NO_DISTANCE", "ZERO", "NO_FIELDS", "NO_M_DIRECTION") # Process: Locate Features Along Routes (2) arcpy.LocateFeaturesAlongRoutes_lr(end_pt, MDTGIS_ROUTES_LRM_DC_MI__2_, "CORRIDOR", "0 Meters", end_pt_loc, Output_Event_Table_Properties__2_, "FIRST", "NO_DISTANCE", "ZERO", "NO_FIELDS", "NO_M_DIRECTION") # Process: Make Table View arcpy.MakeTableView_management(end_pt_loc, end_pt_loc_Vw, "", "", "OBJECTID OBJECTID VISIBLE NONE;RID RID VISIBLE NONE;MEAS MEAS VISIBLE NONE;Distance Distance VISIBLE NONE;RM RM VISIBLE NONE") # Process: Merge arcpy.Merge_management("end_pt_loc_Vw;E:\\MDTAPPS\\interactive\\interactive.mdb\\first_pt_loc", temp, "RID \"CORRIDOR\" true true false 10 Text 0 0 ,First,#,E:\\MDTAPPS\\interactive\\interactive.mdb\\first_pt_loc,RID,-1,-1,end_pt_loc_Vw,RID,-1,-1;beg_offset \"beg_offset\" true true false 8 Double 0 0 ,First,#,E:\\MDTAPPS\\interactive\\interactive.mdb\\first_pt_loc,beg_offset,-1,-1;end_offset \"end_offset\" true true false 8 Double 0 0 ,First,#,end_pt_loc_Vw,end_offset,-1,-1") # Process: Table to Table arcpy.TableToTable_conversion(temp, interactive_mdb, "points", "", "RID \"CORRIDOR\" true true false 10 Text 0 0 ,First,#,E:\\MDTAPPS\\interactive\\interactive.mdb\\temp,RID,-1,-1;beg_offset \"beg_offset\" true true false 8 Double 0 0 ,First,#,E:\\MDTAPPS\\interactive\\interactive.mdb\\temp,beg_offset,-1,-1;end_offset \"end_offset\" true true false 8 Double 0 0 ,First,#,E:\\MDTAPPS\\interactive\\interactive.mdb\\temp,end_offset,-1,-1", "") # Process: Make Route Event Layer (3) arcpy.MakeRouteEventLayer_lr(MDTGIS_ROUTES_LRM_DC, "CORRIDOR", points, "rid LINE beg_offset end_offset", segment, "", "ERROR_FIELD", "NO_ANGLE_FIELD", "NORMAL", "ANGLE", "LEFT", "POINT") # Process: Script1 arcpy.gp.toolbox = "E:/MDTAPPS/interactive/refmseg.tbx"; # Warning: the toolbox E:/MDTAPPS/interactive/refmseg.tbx DOES NOT have an alias. # Please assign this toolbox an alias to avoid tool name collisions # And replace arcpy.gp.Script1(...) with arcpy.Script1_ALIAS(...) arcpy.gp.Script1()