Update ArcGIS Online WebMap Extent Based on Feature Geometry with the ArcGIS API for Python

Table of Contents

Introduction

The ArcGIS API for Python is a powerful Python library that allows users to interact with and automate tasks in ArcGIS Online (or Portal). The API is excellent for programmatically creating, maintaining, and updating webmaps in ArcGIS Online. If you have ever had to reset the extent of a WebMap after it has been let out in the wild for a while, then this workflow is for you. Here, we will focus in updating the extent for one WebMap, but you could certainly iterate through as many as required and update each extent individually as you go along. Please note, that this workflow is for the latest Map Viewer in ArcGIS Online (AGOL) and not for the Classic Viewer.

Geospatial Professionals, GIS Analysts, and enthusiasts will discover the power of automation and script-based operations to efficiently interact and update WebMaps in ArcGIS Online. Throughout this course, you will gain practical, hands-on experience in leveraging the ArcGIS API for Python to perform a wide range of WebMap tasks with ease.

We will dissect WebMaps for all that they are and by the end of this course you will be comfortable with manipulating the JSON, which is the behind the scenes configuration of a WebMap, to produce scripts for workflows where there is currently no API Python method, such as grouping layers.

Below is a WebMap zoomed to the extent of Ireland with some layers added. The original map extent focused on Galway over on the west coast. We will use to API to update/reset the map extent using the geometry of the polygon that represents Galway.

arcgis modules

Versions 2.4.0: The API provides access to your organisations ArcGIS Online via the GIS class in the gis module. This GIS class is the gateway to ArcGIS Online. We will need to import the Map class to create a Map object. The Map class is a part of the map module. This map module provides components for working with 2D and 3D maps and scenes. The Geometry class is imported from the geometry module. The geometry module defines useful geometry types and functions for working with geographic information and GIS functionality.

				
					## import GIS which provides the gateway entry to your AGOL
from arcgis.gis import GIS
## import WebMap from the mapping module
from arcgis.map import Map
## import the Geometry class to get the bounding box for the extent
from arcgis.geometry import Geometry

				
			

Versions <2.4.0: The API provides access to your organisations ArcGIS Online via the GIS class in the gis module. This GIS class is the gateway to ArcGIS Online. We will need to import the WebMap class to create a WebMap object. The WebMap class is a part of the mapping module. This mapping module provides components for working with 2D and 3D maps and scenes, and also includes classes for map layers such as the MapFeatureLayer, MapImageLayer, and VectorTileLayer. The Geometry class is imported from the geometry module. The geometry module defines useful geometry types and functions for working with geographic information and GIS functionality. And lastly we import the FeatureLayer class from the features module. The features module enables us to work efficiently with Feature Services, Feature Layers, and Features.

				
					## import GIS which provides the gateway entry to your AGOL
from arcgis.gis import GIS
## import WebMap from the mapping module
from arcgis.mapping import WebMap
## import the Geometry class to get the bounding box for the extent
from arcgis.geometry import Geometry
## import FeatureLayer class to access the feature we wish to zoom to
from arcgis.features import FeatureLayer
				
			

Accessing ArcGIS Online

Our first port of call is to access your ArcGIS Online via the GIS class. There are a handful of ways to achieve access, if you are logged into your ArcGIS Online in ArcGIS Pro you can simply use "home", otherwise, another common way is to provide the ArcGIS Online URL, followed by your username and password.
				
					## Access AGOL
agol = GIS("home")
				
			
				
					## Access AGOL
agol = GIS(
    url = "https://your_organisation.maps.arcgis.com/",
    username = "Your_Username",
    password = "Your_Password"
)
				
			

Access the WebMap via a Map (or WebMap) Object

Versions 2.4.0: We can create a Map object from an Item object that represents a WebMap in ArcGIS Online. We use the ContentManager get() method and supply in the WebMap item id. The get() method returns an Item object. We then use that WebMap Item object and supply into our Map class to create our Map object.

				
					## the ITEM ID of the WebMap to update
wm_item_id = "WM_ITEM_ID"

## get the WebMap as an Item object
wm_item = agol.content.get(wm_item_id)

## create a Map object from the Item object
webmap = Map(wm_item)
				
			

Versions <2.4.0: We can create a WebMap object from an Item object that represents a WebMap in ArcGIS Online. We use the ContentManager get() method and supply in the WebMap item id. The get() method returns an Item object. We then use that WebMap Item object and supply into our WebMap class to create our WebMap object.

				
					## the ITEM ID of the WebMap to update
wm_item_id = "WM_ITEM_ID"

## get the WebMap as an Item object
wm_item = agol.content.get(wm_item_id)

## create a WebMap object from the Item object
webmap = WebMap(wm_item)
				
			

Get the Bounding Box of the Feature to Zoom to

Version <2.4.0:Let’s think about what we need to achieve. We want to dig into the geometry of a Feature in a Feature Layer. Accessing a WebMap layer alone won’t quite cut it as you cannot get access to features and therefore geometry via this avenue. We need to access the Feature Layer that is referenced by the layer in the WebMap. We can achieve this via the content property for a Map object. The content property returns a MapContent object that has a property called layers which lists the Feature Layer objects for the WebMap.

We create our own little function to retrieve the index of the layer in the map based on the layer name.

Once we have our FeatureLayer object we can interrogate the geometry and get the bounding box of our polygon feature of interest.

				
					def getLayerIndexByName(wm_item, lyr_name):
        try:
            lyr_index = [index for index, lyr in enumerate(wm_item.get_data()["operationalLayers"]) if lyr["title"]==lyr_name][0]
            return lyr_index
        except IndexError:
            return None

## get the index for the layer in the webmap
lyr_index = getLayerIndexByName(wm_item, "ENTER LYR TITLE")

## MapContent layers property returns a list of feature layers (or group layers)
fl = webmap.content.layers[lyr_index]

## Query the layer to return the feature you want to zoom to.
f = fl.query(where="ENTER SQL CLAUSE")

## get the minimum bounding of that feature as an envelope
bbox = Geometry(f.features[0].geometry).envelope
				
			

Version <2.4.0: Let’s think about what we need to achieve. We want to dig into the geometry of a Feature in a Feature Layer. Accessing a WebMap layer alone won’t quite cut it as you cannot get access to features and therefore geometry via this avenue. We need to access the Feature Layer that is referenced by the layer in the WebMap. We can use the WebMap layer URL to achieve this. The code snippet below grabs the URL for the Feature Layer from the WebMap layer of interest.

We create our FeatureLayer object using the FeatureLayer class and supplying the URL from the previous code snippet.

We now have a FeatureLayer object from which we can query and return a Feature object. From this Feature object we can access the JSON geometry and use the Geometry class to create a geometry object and get the bounding box through the envelope property.

				
					## get the url of the layer in the WebMap that we want to zoom to the
## extent of
layer_url = webmap.get_layer(title="ENTER LYR TITLE").url

## get this layer as a FeatureLayer from the Feature Service
fl = FeatureLayer(layer_url, agol)

## Query the layer to return the feature you want to zoom to.
f = fl.query(where="ENTER SQL CLAUSE")

## get the minimum bounding of that feature as an envelope
bbox = Geometry(f.features[0].geometry).envelope
				
			

Update the Map Object (or WebMap Item) with the new Extent

Version 2.4.0: Now that we have the bounding box envelope, we set the extent property for our Map object to the bounding box and then call the update() method on the Map object to commit the change.

				
					## update/add and initialState property to the WebMap
webmap.extent = bbox

## update the WebMap to reflect the new extent
webmap.update()
				
			

Version <2.4.0: Now that we have the bounding box envelope, we create a dictionary to store the update we wish to apply to the extent. We set the "initialState" property in the WebMap definition to our updated extent and then apply the update to the WebMap item.

				
					## create a dictionary as per below
extent = {
    "viewpoint": {
        "targetGeometry": bbox
    }
}

## update/add and initialState property to the WebMap
webmap.definition["initialState"] = extent

## create a dictionary of the new WebMap intem properties
item_properties = {"text":webmap.definition}

## update the WebMap to reflect the new properties
## run the script and then refresh your WebMap to test
wm_item.update(item_properties=item_properties)
				
			

Try it out...

After running the script and refreshing the WebMap, we can see that the extent of the WebMap has altered to the area of interest.

Unlock the full potential of ArcGIS Online by mastering the art of efficient Content Management with the ArcGIS API for Python. In this comprehensive course, you will embark on a journey to streamline your geospatial workflows, enhance data organization, and maximize the impact of your ArcGIS Online platform.

Geospatial Professionals, GIS Analysts, Data Managers, and enthusiasts will discover the power of automation and script-based operations to efficiently manage content in ArcGIS Online. Throughout this course, you will gain practical, hands-on experience in leveraging the ArcGIS API for Python to perform a wide range of content management tasks with ease.

All the code in one place

Version 2.4.0: You can find the entire code workflow below with links to important components in the documentation that were used. The code below is presented slightly different than the blog post. The blog post attempts to show the differences between version 2.4.0 and previous versions.

				
					from arcgis.gis import GIS
from arcgis.map import Map
from arcgis.geometry import Geometry

################################################################################
## API Reference Links:
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.gis.toc.html#gis
##  https://developers.arcgis.com/python/latest//api-reference/arcgis.gis.toc.html#arcgis.gis.ContentManager.get
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.map.toc.html#map
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.map.toc.html#arcgis.map.Map.content
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.map.toc.html#mapcontent
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.map.toc.html#arcgis.map.map_widget.MapContent.layers
##  https://developers.arcgis.com/python/api-reference/arcgis.features.toc.html#arcgis.features.FeatureLayer.query
##  https://developers.arcgis.com/python/api-reference/arcgis.geometry.html
##  https://developers.arcgis.com/python/api-reference/arcgis.geometry.html#geometry
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.map.toc.html#arcgis.map.Map.update
##
## Description:
##  Update WebMap with a new Extent
##
## API Version: 2.4.0
##
################################################################################

################################################################################
## REQUIRED OBJECTS ############################################################

## the ITEM ID of the WebMap to update
wm_item_id = "WM_ITEM_ID"

## the layer name as it appears in the WebMap
lyr_name = "ENTER LYR NAME"

## the SQL clause to limit the geometry
sql_clause = "ENTER SQL CLAUSE"

################################################################################
## FUNCTIONS ###################################################################

def getLayerIndexByName(wm_item, lyr_name):
    try:
        lyr_index = [index for index, lyr in enumerate(wm_item.get_data()["operationalLayers"]) if lyr["title"]==lyr_name][0]
        return lyr_index
    except IndexError:
        return None

################################################################################
## ACCESS AGOL #################################################################

agol = GIS("home")

################################################################################
## CREATE MAP OBJECT ###########################################################

## get the WebMap as an Item object
wm_item = agol.content.get(wm_item_id)

## create a WebMap object from the Item object
webmap = Map(wm_item)

################################################################################
## GET BOUNDING BOX INFO #######################################################

## get the index for the layer in the webmap
lyr_index = getLayerIndexByName(wm_item, lyr_name)

## MapContent layers property returns a list of feature layers (or group layers)
fl = webmap.content.layers[lyr_index]

## Query the layer to return the feature you want to zoom to.
f = fl.query(where=sql_clause)

## get the minimum bounding of that feature as an envelope
bbox = Geometry(f.features[0].geometry).envelope

################################################################################
## UPDATE THE EXTENT ###########################################################

## update/add and initialState property to the WebMap
webmap.extent = bbox

## update the WebMap to reflect the new extent
webmap.update()

################################################################################

				
			

Version <2.4.0: You can find the entire code workflow below with links to important components in the documentation that were used. 

				
					from arcgis.gis import GIS
from arcgis.mapping import WebMap
from arcgis.geometry import Geometry
from arcgis.features import FeatureLayer

################################################################################
## API Reference Links:
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.gis.toc.html#gis
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.gis.toc.html#arcgis.gis.ContentManager.get
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.mapping.toc.html#webmap
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.mapping.toc.html#arcgis.mapping.WebMap.get_layer
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.features.toc.html#arcgis.features.FeatureLayer.query
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.geometry.html
##  https://developers.arcgis.com/python-2-3/api-reference/arcgis.geometry.html#geometry
##
## Description:
##  Update WebMap with a new Extent
##
## API Version: 2.2.0.1
##
################################################################################

## Access AGOL
agol = GIS("home")

## the ITEM ID of the WebMap to update
wm_item_id = "WM_ITEM_ID"

## get the WebMap as an Item object
wm_item = agol.content.get(wm_item_id)

## create a WebMap object from the Item object
webmap = WebMap(wm_item)

## get the url of the layer in the WebMap that we want to zoom to the
## extent of
layer_url = webmap.get_layer(title="ENTER LYR TITLE").url

## get this layer as a FeatureLayer from the Feature Service
fl = FeatureLayer(layer_url, agol)

## Query the layer to return the feature you want to zoom to.
f = fl.query(where="ENTER SQL CLAUSE")

## get the minimum bounding of that feature as an envelope
bbox = Geometry(f.features[0].geometry).envelope

## create a dictionary as per below
extent = {
    "viewpoint": {
        "targetGeometry": bbox
    }
}

## update/add and initialState property to the WebMap
webmap.definition["initialState"] = extent

## create a dictionary of the new WebMap intem properties
item_properties = {"text":webmap.definition}

## update the WebMap to reflect the new properties
## run the script and then refresh your WebMap to test
wm_item.update(item_properties=item_properties)
				
			

Leave a Comment

Your email address will not be published. Required fields are marked *