{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Exploring ArcGIS REST Services\n",
"Data served via ArcGIS Servers support a REST API for accessing these services. This notebook provides some examples on how we can use Python to access these services using the `requests` package. \n",
"\n",
"→ Full documentation on the ArcGIS REST API: https://developers.arcgis.com/rest/services-reference/get-started-with-the-services-directory.htm"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### NCOneMap's REST Endpoint\n",
"We'll explore NCOneMap's web services, accessed here: https://services.nconemap.gov/secure/rest/services. \n",
"* Begin by navigating to that page to familiarize yourself with the organization and listing of individual services, i.e. the [Services Directory](https://developers.arcgis.com/rest/services-reference/using-the-services-directory.htm).\n",
" * You'll see a number of folders containing other services and below that a number of services listed there in the main page. \n",
" * Note the types of services listed: `ImageServer`, `FeatureServer`, `MapServer`. These services provide access to different types of data. Other services provide access to data processing capabilities. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Next, click on the [`NC1Map_Census (MapServer)`](https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer) link to open the metadata for that [map service](https://developers.arcgis.com/rest/services-reference/map-service.htm).\n",
" * You'll see a number of **properties** for the map service including a `Description`, a list of `Layers` included in that service, `Spatial Reference`, and at the very bottom, a list of the `Supported operations`. \n",
" * We'll explore how we can use the [`Export Map`](https://developers.arcgis.com/rest/services-reference/export-map.htm)operation to extract data from this service. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Click on the ['Export Map'](https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer/export?bbox=115398.88167874969,137561.22299815627,951284.8934306827,392245.24220382335) link at the bottom of the map service metadata page. \n",
" * Note the URL in the page that appears: This is a REST-based request. And the page that appears is a nifty form to help you edit and explore that REST-based URL. \n",
" * Change the bounding box values to: `-79.3, 35, -77.9, 36.5`\n",
" * Since those coordinates we just supplied are in NAD 83 geographic coordinates, set the bounding box spatial reference to the WKID of `4269`\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" * Click **Export Map (GET)** to generate the [URL](https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer/export?bbox=-79.3%2C+35%2C+-77.9%2C+36.5&bboxSR=4269&layers=&layerDefs=&size=&imageSR=&format=png&transparent=false&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&rotation=&datumTransformations=&layerParameterValues=&mapRangeValues=&layerRangeValues=&f=html) reflecting our changes and display the results."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" * Enter `show:0` in the Layers: box to show only the first layer contained in this map service (1970 Census Boundary/Population). Upate the map by hitting **Export Map (GET)** again. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" * Change the Format from `HTML` to `Image` and hit **Export Map (GET)** again. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" * Copy the [URL](https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer/export?bbox=-79.3%2C+35%2C+-77.9%2C+36.5&bboxSR=4269&layers=show%3A0&layerDefs=&size=&imageSR=&format=png&transparent=false&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&rotation=&datumTransformations=&layerParameterValues=&mapRangeValues=&layerRangeValues=&f=image) of the generated page and past between the quotes in code block below and run it. *We've captured that same image!* "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import Image\n",
"Image(url='https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer/export?bbox=-79.3%2C+35%2C+-77.9%2C+36.5&bboxSR=4269&layers=show%3A0&layerDefs=&size=&imageSR=&format=png&transparent=false&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&rotation=&datumTransformations=&layerParameterValues=&mapRangeValues=&layerRangeValues=&f=image')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Dissecting a Map Service REST request\n",
"Now let's dissect that URL into a service endpoint (its address) and a list of parmaters. \n",
"\n",
"Below is the full url: \n",
"```html\n",
"https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer/export?bbox=-79.3%2C+35%2C+-77.9%2C+36.5&bboxSR=4269&layers=show%3A0&layerDefs=&size=&imageSR=&format=png&transparent=false&dpi=&time=&layerTimeOptions=&dynamicLayers=&gdbVersion=&mapScale=&rotation=&datumTransformations=&layerParameterValues=&mapRangeValues=&layerRangeValues=&f=image\n",
"```\n",
"\n",
"Everything up to the `?` is the **service end point** (the server's internet address and the service location). Everything after that are **parameters** separated by `&`. \n",
"\n",
"* Break those into components we can use with the `requests` package, i.e. a URL variable and a dictionary of parmeter name:value pairs. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"theURL = 'https://services.nconemap.gov/secure/rest/services/NC1Map_Census/MapServer/export'\n",
"params = {\"bbox\":\"-79.3, 35,-77.9, 36.5\",\n",
" \"bboxSR\":\"4269\",\n",
" \"layers\":\"show:0\",\n",
" \"layerDefs\":\"\",\n",
" \"size\":\"\",\n",
" \"imageSR\":\"\",\n",
" \"format\":\"png\",\n",
" \"transparent\":\"false\",\n",
" \"dpi\":\"\",\n",
" \"time\":\"\",\n",
" \"layerTimeOptions\":\"\",\n",
" \"dynamicLayers\":\"\",\n",
" \"gdbVersion\":\"\",\n",
" \"mapScale\":\"\",\n",
" \"rotation\":\"\",\n",
" \"datumTransformation\":\"\",\n",
" \"layerParameterValue\":\"\",\n",
" \"mapRangeValues\":\"\",\n",
" \"layerRangeValues\":\"\",\n",
" \"f\":\"image\"\n",
" } "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* Now, let's import the `requests` package and execute our REST request. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#import the modules\n",
"import requests"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"response = requests.get(theURL, params)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import Image\n",
"Image(response.content)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ok, it's just the same as above, but we can easily change values in our `params` dict and modify the output. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#Zoom more into Durham and show a different layer\n",
"params['bbox'] = '-79.0, 35.85, -78.8, 36.25'\n",
"params['layers'] = 'show:8'\n",
"response = requests.get(theURL, params)\n",
"Image(response.content)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"#Add a layer definition to just show durham county\n",
"params['layerDefs']=\"{8:GEOID10 LIKE '37063%'}\"\n",
"response = requests.get(theURL, params)\n",
"Image(response.content)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}