Geoprocessing service that returns features to ArcMap

4996
13
Jump to solution
06-24-2015 10:36 AM
BrendanDwyer
Occasional Contributor

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

1 Solution

Accepted Solutions
FilipKrál
Occasional Contributor III

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.

View solution in original post

13 Replies
FilipKrál
Occasional Contributor III

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.

BrendanDwyer
Occasional Contributor

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.

0 Kudos
FilipKrál
Occasional Contributor III

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,

BrendanDwyer
Occasional Contributor

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

TerryGustafson
Occasional Contributor II

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

0 Kudos
FilipKrál
Occasional Contributor III

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.

0 Kudos
TerryGustafson
Occasional Contributor II

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.

0 Kudos
FilipKrál
Occasional Contributor III

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:

  • The in_table parameter of MakeEventLayer tool should be a Table View so I'd call MakeTableView on the "points" table before you pass it to MakeRouteEventLayer(3).
  • The output of MakeRouteEventLayer is a layer stored in memory of the computer but that does not mean it is in an in-memory workspace. Anyhow, I'd try making the final layer "segment" persistent by calling CopyFeatures on it. Even CopyFeatures to in_memory\something might help.

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.

TerryGustafson
Occasional Contributor II

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()
0 Kudos