Select to view content in your preferred language

Can I return a list of attribute values from a geoprocessing service?

6517
19
Jump to solution
07-13-2012 06:03 AM
TracySchloss
Honored Contributor
I have been asked to create a service that will be consumed by a non-GIS application.   The programmer wants to be able to "make a call to GIS" providing the number of a school district as input.  They want the service to return just a list of districts that surround the input number.  Their application will be written in Java, which I know nothing about.

I have considered publishing a model as a geoprocessing service and I have looked at Python.  It seems like I might have more luck in Python, which I've never used before, because at least I could make an array or list of values from the attributes?  I'm not finding much documentation on publishing a Python script as a geoprocessing service.  I assume I can do this?

I started by creating a model that had the tools select by attribute and select by location.   Then I exported this to Python.  It executes OK when I'm in ArcMap.   I'm not sure where to go from there.  I know I need to examine each polygon that is the result of the select by location query and find just the attribute of the district field.

There is no desire to view or create a map in this application.  They just want a list containing the numbers of the adjacent districts.  Even after I get the list,  I'm still not sure what I might need to do to get this to work properly as an ArcGIS Server geoprocessing service.  I am still at version 10.0.

# --------------------------------------------------------------------------- # adjacent.py # Created on: 2012-07-12 15:14:17.00000 #   (generated by ArcGIS/ModelBuilder) # Usage: adjacent <countyName>  # Description:  # ---------------------------------------------------------------------------  # Import arcpy module import arcpy  # Set Geoprocessing environments arcpy.env.scratchWorkspace = "C:\\ESRItest\\model\\process.gdb" arcpy.env.workspace = "C:\\ESRItest\\model\\process.gdb"  # Script arguments countyName = arcpy.GetParameterAsText(0) if countyName == '#' or not countyName:     countyName = "Boone" # provide a default value if unspecified  # Local variables: selected_County = countyName Adjacent_Counties = selected_County county = "county"  # Process: Select Layer By Attribute arcpy.SelectLayerByAttribute_management(county, "NEW_SELECTION", "\"NAME\" = '%countyName%'")  # Process: Select Layer By Location result = arcpy.SelectLayerByLocation_management(selected_County, "BOUNDARY_TOUCHES", "", "", "NEW_SELECTION")  ## NOW WHAT?
Tags (2)
0 Kudos
19 Replies
TracySchloss
Honored Contributor
My original thought process was the one that Kevin is describing.  The request that was made to us was "we want to make a call to GIS with a school district number and get returned back to our program as a list of adjacent school district numbers in a comma delimited format".   My sample code is county boundaries instead, because I had those already created.  (The school districts are in the process of being updated. ) 

When I was first handed this request, I thought it was more map centric and wrote a small FLEX app to do this (my only area of real programming expertise).  However, they don't WANT to interact with the map.  Per the last conversation we had "They just want a list". Even Copy Rows is going to require them to parse the JSON output to retrieve just the district ID from each of the rows.  I figure they are going to have to figure out themselves how to parse what GIS can output.

Part of my problem seems to be that my original code doesn't seem to be selecting anything when I run it as Python.  I need to go back to my original model and see if it was truly executing.  It's just a select by attribute with that output passed as the input to select by location - it ought to be a piece of cake!
0 Kudos
KevinHibma
Esri Regular Contributor
Ok, since you know exactly what they want, you have 2 options (that I can see anyway).
Once you get your select working, you're done - have them parse your JSON. 🙂
Or, if you're in a helping mood, take the suggestion from Chris which uses a cursor, grab the required IDs and build them into a string. Make the output of your service just that - a comma delimited string.
0 Kudos
ChristopherThompson
Frequent Contributor
looking back at your original code the biggest issue is that as it appears in your posting, there isn't a feature class being referenced anywhere
Select by Attributes references some text named "county" and Selecty by Location references something called selectedCounty which is simply the text value of the county name. The code should look something like this:

county = 'filepath to a feature class on disk'

# Process: Select Layer By Attribute
county_selection = arcpy.SelectLayerByAttribute_management(county, "NEW_SELECTION", "\"NAME\" = '%countyName%'")

# Process: Select Layer By Location
result = arcpy.SelectLayerByLocation_management(county_selection, "BOUNDARY_TOUCHES", "", "", "NEW_SELECTION")


in this example, county is an object that references an on disk feature class and is used in the Select by Attribute process to create an object named county_selection.

county_selection is then passed in to the Select by Location process which creates the object result which gets used by the search cursor that we discussed earlier.

Its possilbe that county needs to be a feature layer in which case you would do something like this:
county = arcpy.MakeFeatureLayer_management(<feature class on disk>, "outlayer name")
0 Kudos
TracySchloss
Honored Contributor
I did realize somewhere along the way that I couldn't use a featureclass as input. 

I'm getting confused on whether I should run this  from the python shell or if I can run it as a script in a toolbox.  If I run it as a script, it gives me the prompt I expect for the name, but it doesn't seem to return anything.  There aren't any errors, either.  I'm not sure there's even a place for my results to go since it's just returning a list and not anything like a layer or table.

If I run it through the shell, then when do I specify my input string to search on?

Also I'm wondering about the syntax of my expression in select by attributes.  When I tried hard coding in a county name "NAME" = 'Holt', it created my output list (YEAH!).  But when I put back it back in as a variable, it doesn't list anything (BOO!)  I had a few lines in there for CopyFeatures, but I don't really think I need that, so I commented it out.  Since select by attribute isn't finding anything, then select by location logically isn't either and I end up finding nothing.

# ---------------------------------------------------------------------------
# adjacent.py
# Created on: 2012-07-12 15:14:17.00000
#   (generated by ArcGIS/ModelBuilder)
# Usage: adjacent <countyName> 
# Description: 
# ---------------------------------------------------------------------------

# Import arcpy module
import arcpy

# Set Geoprocessing environments
arcpy.env.scratchWorkspace = "C:\\ESRItest\\model\\process.gdb"
arcpy.env.workspace = "C:\\ESRItest\\model\\process.gdb"

#overwrite pre-existing files
arcpy.env.overwriteOutput = True

# Script arguments
countyName = arcpy.GetParameterAsText(0)
if countyName == '#' or not countyName:
    countyName = "Boone" # provide a default value if unspecified

# Local variables:
county = "county"
county_Layer = "county_Layer"
countyList = []

txt_list = ""
#Output_Feature_Class = "C:\\ESRItest\\model\\process.gdb\\county_CopyFeaturesOutput"

# Process: Make Feature Layer
county_Layer = arcpy.MakeFeatureLayer_management("C:\ESRItest\model\process.gdb\county", county_Layer, "", "", "OBJECTID OBJECTID VISIBLE NONE;Shape Shape VISIBLE NONE;NAME NAME VISIBLE NONE;CNTY_FIPS CNTY_FIPS VISIBLE NONE;FIPS FIPS VISIBLE NONE;POP2005 POP2005 VISIBLE NONE;POP05_SQMI POP05_SQMI VISIBLE NONE;SQMI SQMI VISIBLE NONE;NAME2 NAME2 VISIBLE NONE;Shape_Length Shape_Length VISIBLE NONE;Shape_Area Shape_Area VISIBLE NONE")

#Process: Select Layer By Attributes
countySelection = arcpy.SelectLayerByAttribute_management(county_Layer, "NEW_SELECTION", "\"NAME\" = '%countyName%' ")
# Process: Select Layer By Location
results = arcpy.SelectLayerByLocation_management(countySelection, "INTERSECT", "", "", "NEW_SELECTION")

# Process: Copy Features
#arcpy.CopyFeatures_management(county_Layer, Output_Feature_Class, "", "0", "0", "0")
## Step through the selection to get the values from the name field

rows = arcpy.SearchCursor(results,"","","NAME","NAME")
for row in rows:
  neighborVal = row.getValue("NAME")
  countyList.append(neighborVal)
  txt_list = ','.join(countyList)
print txt_list


It feels very close!  I am happy to see those county names listed out in my shell window, even if they aren't yet working when I use a variable instead.
0 Kudos
KevinBell
Deactivated User
I'm trying to return a string from a gp service.  I'm starting with a pyt below, but I don't see how to populate the output param1 here.  any ideas?

import arcpy


class Toolbox(object):
    def __init__(self):
        """Define the toolbox (the name of the toolbox is the name of the
        .pyt file)."""
        self.label = "ForestStats"
        self.alias = ""

        # List of tool classes associated with this toolbox
        self.tools = [getSummary]


class getSummary(object):
    def __init__(self):
        """Define the tool (tool name is the name of the class)."""
        self.label = "GetData"
        self.description = ""
        self.canRunInBackground = False

    def getParameterInfo(self):
        """Define parameter definitions"""

        param0 = arcpy.Parameter(
                displayName="Area of Interest",
                name="in_area",
                datatype="String",
                parameterType="Required",
                direction="Input")
        
        param1 = arcpy.Parameter(
            displayName="Forest Statistics",
            name="forest_statistics",
            datatype="String",
            parameterType="Derived",
            direction="Output")    
        
        params = [param0, param1]
        return params


    def isLicensed(self):
        """Set whether tool is licensed to execute."""
        return True



    def execute(self, parameters, messages):
        """The source code of the tool."""
 d = {}
        tbl = r'E:\gis\forestry\20120711_forestryWebApp\Forestry.gdb\wholeCity'
 with arcpy.da.SearchCursor(tbl, ('rangeClass', 'count')) as c:
     for r in c:
  d[r[0]] = r[1]
 
 print d
 arcpy.AddMessage(str(d))
 
 #params[1] = str(d)
        return 


It adds the message just fine...  How do i pass str(d) to the output param1?  Once I do this, I should have a gp service that returns some good clean data!
0 Kudos
ChristopherThompson
Frequent Contributor
I did realize somewhere along the way that I couldn't use a featureclass as input.  

I'm getting confused on whether I should run this from the python shell or if I can run it as a script in a toolbox. If I run it as a script, it gives me the prompt I expect for the name, but it doesn't seem to return anything. There aren't any errors, either. I'm not sure there's even a place for my results to go since it's just returning a list and not anything like a layer or table. 

If I run it through the shell, then when do I specify my input string to search on?  


Since this is something that may get called by another application (your developer's java app) I think you want this to run from the shell rather than as something that is interacted with through toolbox. In that scenario you need to be able to supply python with the input variable that is the county name. To get user input from a python script that you run from the shell use 'raw_input' - this is implemented like this:

input_county = raw_input('What County do you want to select?')

that will prompt the user for a value and then that value (stored in the input_county variable) can be passed into the selection query in your Select by Attributes process:

selection = arcpy.SelectLayerByAttribute_management(Output_Layer, "NEW_SELECTION", "\"NAME\" = input_county")

You and your java developer might take a look at this blog post to see how you get something out of a python script:
http://norwied.wordpress.com/2012/03/28/call-python-script-from-java-app/
The other piece of the puzzle that I don't know just yet is how you get the county name INTO python.. I don't know if thats something that needs to get passed in from Java (say the app has a form that a person selects a county name from a drop down...), or if you implement the raw_input method if that will work as it does when you run python from the shell.
0 Kudos
ChristopherThompson
Frequent Contributor
I'm trying to return a string from a gp service....How do i pass str(d) to the output param1?  Once I do this, I should have a gp service that returns some good clean data!


Kevin, nice hijack of someone else's thread 🙂
I'd suggest posting your question in its own thread as it will probably get more attention that way and there are a number of issues here that aren't related to the current one - script tools, the setting of parameters for a script tool and the use of dictionaries.
0 Kudos
TracySchloss
Honored Contributor
The input worked fine in that I got a prompt.  Since I'd been using countyName as my varable I just set it as

countyName = raw_input('What County do you want to select?')


When I tried your expression as-is,

countySelection = arcpy.SelectLayerByAttribute_management(county_Layer, "NEW_SELECTION", "\"NAME\" = countyName")


it told me I had a syntax error:

Traceback (most recent call last):
  File "C:\ESRItest\model\adjacent.py", line 36, in <module>
    countySelection = arcpy.SelectLayerByAttribute_management(county_Layer, "NEW_SELECTION", "\"NAME\" = countyName")
  File "C:\Program Files\ArcGIS\Desktop10.0\ArcPy\arcpy\management.py", line 4259, in SelectLayerByAttribute
    raise e
ExecuteError: ERROR 000358: Invalid expression
Failed to execute (SelectLayerByAttribute).
I figured it wanted some quotes, so I changed it to
countySelection = arcpy.SelectLayerByAttribute_management(county_Layer, "NEW_SELECTION", "\"NAME\" = 'countyName'")


This didn't error, but it didn't return anything either!

Thanks for the suggestion of another thread for a question that is only vaguely related to mine!
0 Kudos
TracySchloss
Honored Contributor
This one works.  I spent an hour trying to figure out how to manage the quotes properly in my expression!

# --------------------------------------------------------------------------- # adjacent.py # Created on: 2012-07-12 15:14:17.00000 #   (generated by ArcGIS/ModelBuilder) # Usage: adjacent <countyName>  # Description:  # ---------------------------------------------------------------------------  # Import arcpy module import arcpy  # Set Geoprocessing environments arcpy.env.scratchWorkspace = "C:\\ESRItest\\model\\process.gdb" arcpy.env.workspace = "C:\\ESRItest\\model\\process.gdb"  #overwrite pre-existing files arcpy.env.overwriteOutput = True  # Script arguments #countyName = arcpy.GetParameterAsText(0) countyName = raw_input('What County do you want to select?')  # Local variables: county = "county" county_Layer = "county_Layer" countyList = [] txt_list = ""  #Output_Feature_Class = "C:\\ESRItest\\model\\process.gdb\\county_CopyFeaturesOutput"  # Process: Make Feature Layer county_Layer = arcpy.MakeFeatureLayer_management("C:\ESRItest\model\process.gdb\county", county_Layer, "", "", "OBJECTID OBJECTID VISIBLE NONE;Shape Shape VISIBLE NONE;NAME NAME VISIBLE NONE;CNTY_FIPS CNTY_FIPS VISIBLE NONE;FIPS FIPS VISIBLE NONE;POP2005 POP2005 VISIBLE NONE;POP05_SQMI POP05_SQMI VISIBLE NONE;SQMI SQMI VISIBLE NONE;NAME2 NAME2 VISIBLE NONE;Shape_Length Shape_Length VISIBLE NONE;Shape_Area Shape_Area VISIBLE NONE")  #Process: Select Layer By Attributes  #print countyName  whereClause=" \"NAME\" = " + "'"+countyName+"'" #print whereClause countySelection = arcpy.SelectLayerByAttribute_management(county_Layer, "NEW_SELECTION", whereClause)  # Process: Select Layer By Location results = arcpy.SelectLayerByLocation_management(countySelection, "BOUNDARY_TOUCHES", "", "", "NEW_SELECTION")  # Process: Copy Features #arcpy.CopyFeatures_management(county_Layer, Output_Feature_Class, "", "0", "0", "0") ## Step through the selection to get the values from the name field  rows = arcpy.SearchCursor(results,"","","NAME","NAME") for row in rows:   neighborVal = row.getValue("NAME")   if neighborVal != countyName:       countyList.append(neighborVal)   txt_list = ','.join(countyList) print txt_list


I still need to figure out how in the world to manage this as a call from Java.  At least I can give input and receive output from within the Python window.

Thanks so much Chris for your assistance!!!!!
0 Kudos
ChristopherThompson
Frequent Contributor
Tracy good luck!  I would be interested to see how you work out the implementation of this in the Java app - if you would post your solution that would be very cool.

ct
0 Kudos