Parcel Center XY: Using ArcGIS Server REST API

We currently have a business need to get at parcel center points using parcel numbers.  If some of our business systems can communicate using HTTP, I thought using the ArcGIS Server REST API with our map service would be ideal.  But first I needed to figure out how to do it.  What better way to test the concept by building a Python script!

If the query option for your map service is turned on, then you can query your features in the map service to get at information you need.  For this project, we need to get at the center point of a given parcel.  I will save you the long story here, you cannot directly through the map service REST API.  However, you can if you have the geometry of the parcel and pass that to a Geometry Service to calculate the center point.

Here is the script that does just that.  I added some comments so you can see what is going on.

# Import needed modules

import sys,urllib2,json

# Get parcel number

parnum = str(sys.argv[1])

# Set the output spatial reference to WGS84 decimal degrees

sr = 4326

# Build REST query url to get parcel geometries

base_url = "http://<our_server>/arcgis/rest/services/<map_service_name>/MapServer/<layer_number>/query"
query = "?where=AIN='{}'&returnGeometry=true&outSR={}&f=json".format(parnum, sr)
urlstring = base_url + query

# Execute REST query to get parcel geometries back

j = urllib2.urlopen(urlstring)
js = json.load(j)
pargeojson = js["features"][0]["geometry"]
pargeostr = "[" + json.dumps(pargeojson).replace(" ", "") + "]"

# Build REST query to get parcel center xy

base_url2 = "http://<our_server>/arcgis/rest/services/Utilities/Geometry/GeometryServer/labelPoints"
query2 = "?sr={}&polygons={}&f=json".format(sr, pargeostr)
urlstring2 = base_url2 + query2

# Execute REST query to get parcel center xy back

j2 = urllib2.urlopen(urlstring2)
js2 = json.load(j2)
parcenx = js2["labelPoints"][0]["x"]
parceny = js2["labelPoints"][0]["y"]

# Return parcel center xy

print parcenx,parceny

Since I work on a Windows workstation, I would execute this script at the DOS prompt like so:

C:\test\parcenxy.py ##########

Where ########## is a valid parcel number.

Note that the output spatial reference number I used (4326) was for decimal degrees.  Even though our map service is using a different spatial reference, the service query will output decimal degree coordinates.  If you need something different, enter your WKID number there.

For the map service query string, we have a field named AIN and make it equal to the given parcel number and specify we want geometry back in our output spatial reference and return the info in JSON format.  Note the curly brackets {} are used by .format to insert the parcel number and spatial reference number into the query string.  Here is what it would look like using a parcel number of 2469022030:

http://<our_server>/arcgis/rest/services/<map_service_name>/MapServer/<layer_number>/query?where=AIN='2469022030'&returnGeometry=true&outSR=4326&f=json

The query is executed by using urllib2 module to open the URL to return a file-like object, then the json module is used to deserialize the file-like object containing the JSON document.  Quite a bit of JSON info is retured, so I only extract the part that contains the geometry for the returned parcel, which is contained as the first value the “features” key and the coordinate values are in the “geometry” key.  Extracting that I prepare the coordinate information by removing all spaces and then placing square backets [] around them to be used in the next query.  Here is what that looks like:

[{"rings":[[[-118.32316916745269,34.19613307435951],[-118.322990074084,34.195999593524576],[-118.32300819714426,34.19598270084718],[-118.32310209716347,34.1958925120099],[118.323125314743,34.19591028326712],[-118.32345863442863,34.19616010947092],[-118.32334825716335,34.19626518190225],[-118.32316916745269,34.19613307435951]]]}]

The next query is to get at the parcel center coordinates.  Here I used the labelPoints geometry service which calculates the center point for the polygon.  Note I used the spatial reference again to tell the geometry service what spatial reference system the given coordinate are in.  Here is what that URL looks like:

http://<our_server>/arcgis/rest/services/Utilities/Geometry/GeometryServer/labelPoints?sr=4326&polygons=[{"rings":[[[-118.32316916745269,34.19613307435951],[-118.322990074084,34.195999593524576],[-118.32300819714426,34.19598270084718],[-118.32310209716347,34.1958925120099],[-118.323125314743,34.19591028326712],[-118.32345863442863,34.19616010947092],[-118.32334825716335,34.19626518190225],[-118.32316916745269,34.19613307435951]]]}]&f=json

ArcGIS Server comes with geometry services by default, however, I have found some sites without them which tells me they have been turned off for some reason.  Make sure you have it too.

The JSON returned by the geometry service query has the X and Y coordinate values stored in the “labelPoints” key.  Here is what that looks like:

{'labelPoints': [{'y': 34.19607918600008, 'x': -118.32322422599998}]}

Extracting that out and printing the results returns the coordinates:

-118.323224226 34.196079186

This all happens for me in 0.05 seconds after the map service warms up!

By the way, if the parcel is a multi-part parcel (many polygons that make up one parcel), the returned center point will be from the largest polygon in that group.

The script does not check for an entered parcel number or check the returned JSON to see if there is any geometry for the entered parcel, so it will blow up in those cases.  But this was just an exercise to see if I can do this.

The next thing to do is turn this script into an ArcGIS Server service so other systems can get back a given parcel’s center point.  That is for another day!  Enjoy the script.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s