Reorder ArcGIS Online WebMap Layers with the ArcGIS API for Python and a Custom ArcGIS Pro Tool

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 and feature layers in ArcGIS Online. In this post we will focus on updating a webmap by altering the order of layers. While the main workflow is with the ArcGIS API for Python, we will use a sprinkle of ArcPy for the tool input parameters and create a custom tool within ArcGIS Pro to perform the reordering.  

arcgis modules

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. We also need to import arcpy to cater for our input parameters when creating a custom tool with ArcGIS Pro.

				
					## 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 arcpy for our input parameters
import arcpy
				
			

Define the parameters

				
					## the item id for the WebMap you wish to reorder layers for.
wm_item_id = arcpy.GetParameterAsText(0)

## the new order for the layers.
reorder = arcpy.GetParameterAsText(1)
				
			

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"
)
				
			

Create a WebMap Object

We create the WebMap object from an Item object.
				
					## access the WebMap Item
wm_item = agol.content.get("WM_ITEM_ID")

## create a WebMap object
webmap = WebMap(wm_item)
				
			

The Re-order List

We take the input from our reorder parameter which will come in as ; separated text with each layer name wrapped in single quotes. We remove the single quotes and convert the string to a list.
				
					## creates a list of layer names from the reorder input
reorder_list = reorder.replace("'", "").split(";")
				
			

The Old Layer Order

We want the definitions for all the current layers as an entry in a dictionary where the key of the dictionary is the layer name, and the value of the dictionary is the layer definition.

				
					## this will hold the current JSON for the layers:
##    key-lyr_title, value-lyr definition
lyr_json_dict = {}

## populate the lyr_json_dict
for lyr in webmap.definition.operationalLayers:
    lyr_json_dict[lyr["title"]] = lyr

				
			

The New Layer Order

The operationalLayers property for a WebMap item definition is a list. We create an empty list that we will populate with layer definitions in the order we want the WebMap to display them. Index zero(0), the first layer in the list is the bottom-most layer of the map and each incrementing index/layer sits on top, one on top of the next.
				
					## create an empty list to hold the reordered layers (operationalLayers)
new_ol = []

## populate the new operational layers list
for lyr_name in reorder_list:
    new_ol.append(lyr_json_dict[lyr_name])
				
			

Update the WebMap Item Definition

Commit the change and witness the reordering of the WebMap layers.

				
					## set the operationalLayers property to our new list of layers reordered
webmap.definition.operationalLayers = new_ol

## we need to update the item definition for the reorder to take affect
item_properties = {"text":webmap.definition}
wm_item.update(item_properties=item_properties)
				
			

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.

Create the tool in ArcGIS Pro

There’s not too many lines of code there really! There’s probably more comments in there than actual lines of working code. Save your script and let’s head over to ArcGIS Pro to create our custom tool for use.

Right-click on your toolbox/toolset of choice and select New > Script. The New Script window will appear. In the General tab set Name to ReorderWebMapLayersLabel to Reorder WebMap Layers, and the Description and Summary asbelow or something more descriptive.

In the Parameters tab set as per below. Set the WebMap Item ID with a Data Type of String, and also set the Layer Re-ordering with a Data Type of String and select Multiple Values.

In the Execution tab, click the folder icon in the top-right corner and add your saved Python script.

In the Validation, at the top add the imports and access AGOL as per below.

Update the code in the updateParameters() as per below. This w

				
					from arcgis.gis import GIS
from arcgis.mapping import WebMap
agol = GIS("home")


    def updateParameters(self):
        # Modify the values and properties of parameters before internal
        # validation is performed.
        if self.params[0].value:
            if not self.params[1].altered:
                wm = WebMap(agol.content.get(self.params[0].valueAsText))
                lyrs = [lyr.title for lyr in wm.definition.operationalLayers]
                self.params[1].filter.list = lyrs
                self.params[1].values = lyrs
        return
				
			

The tool in action

I have a webmap with six layers. I want to move the County Boundaries layer to the bottom and the NIAH layer to the top.

In ArcGIS Pro open up our Reorder WebMap Layers tool.

Add a WebMap Item ID and the current layer order will populate.

It would be nice if you could drag and reorder but unfortunately at time of publishing you need to right-click to he left on an entry and move up or down. I’ll move the NIAH to the bottom of the list, this represents the top layer in a webmap, and the County Boundaries to the top, which represents the bottom-most layer in a webmap.

I’ll run the tool and refresh the WebMap page to see the layer reordering reflected.

All the code in one place

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
import arcpy

################################################################################
## API Reference Links:
##  https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#gis
##  https://developers.arcgis.com/python/api-reference/arcgis.mapping.toc.html#webmap
##  https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#arcgis.gis.ContentManager
##  https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#arcgis.gis.Item.update
##  https://pro.arcgis.com/en/pro-app/latest/arcpy/functions/getparameterastext.htm
##
## Based on a solution I provided on Esri Communities
##  https://community.esri.com/t5/arcgis-api-for-python-questions/reorder-webmap-layers-with-python/td-p/797542
##
## API Version: 2.3.0
##
################################################################################
## USER INPUTS #################################################################

## the item id for the WebMap you wish to reorder layers for.
wm_item_id = arcpy.GetParameterAsText(0)

## the new order for the layers.
reorder = arcpy.GetParameterAsText(1)

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

agol = GIS("home")

################################################################################
## ACCESS THE WEBMAP ITEM ######################################################

## get the webmap as an item object
wm_item = agol.content.get(wm_item_id)

################################################################################
## CREATE A WEBMAP OBJECT ######################################################

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

################################################################################
## THE REORDER LIST ############################################################

## creates a list of layer names from the reorder input
reorder_list = reorder.replace("'", "").split(";")

################################################################################
## THE OLD ORDER ###############################################################

## this will hold the current JSON for the layers:
##    key-lyr_title, value-lyr definition
lyr_json_dict = {}

## populate the lyr_json_dict
for lyr in webmap.definition.operationalLayers:
    lyr_json_dict[lyr["title"]] = lyr

################################################################################
## THE NEW ORDER ###############################################################

## create an empty list to hold the reordered layers (operationalLayers)
new_ol = []

## populate the new operational layers list
for lyr_name in reorder_list:
    new_ol.append(lyr_json_dict[lyr_name])

################################################################################
## UPDATE THE WEBMAP ITEM DEFINITION ###########################################

## set the operationalLayers property to our new list of layers reordered
webmap.definition.operationalLayers = new_ol

## we need to update the item definition for the reorder to take affect
item_properties = {"text":webmap.definition}
wm_item.update(item_properties=item_properties)

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

				
			

2 thoughts on “Reorder ArcGIS Online WebMap Layers with the ArcGIS API for Python and a Custom ArcGIS Pro Tool”

  1. This is an excellent post!
    I am trying to adjust this code so that in the script tool, the user is given a list of all web maps that they own. Once selected, the layers are listed similarly to your post. The only issue that I am having is that when I adjust a layer, the layer list refreshes. Any thoughts?

    Here is my validation code:

    from arcgis.gis import GIS
    from arcgis.mapping import WebMap
    agol = GIS(“home”)

    class ToolValidator:
    # Class to add custom behavior and properties to the tool and tool parameters.

    def __init__(self):
    # Set self.params for use in other validation methods.
    self.params = arcpy.GetParameterInfo()
    self.previous_webmap_name = None

    def initializeParameters(self):
    # Customize parameter properties. This method gets called when the
    # tool is opened.
    user_content = agol.content.search(query=”owner:” + agol.users.me.username, item_type=”Web Map”, max_items = 100)
    web_maps = sorted([item.title for item in user_content])
    self.params[0].filter.list = web_maps
    self.previous_webmap_name = None

    return

    def updateParameters(self):
    # Modify the values and properties of parameters before internal
    # validation is performed.
    current_webmap_name = self.params[0].valueAsText

    # Update layers only if the web map name has changed
    if current_webmap_name and current_webmap_name != self.previous_webmap_name:
    search_results = agol.content.search(query=f”title:{current_webmap_name} AND owner:{agol.users.me.username}”, item_type=”Web Map”)

    # Iterate through the search results to find the exact match
    for item in search_results:
    if item.title == self.params[0].valueAsText:
    wm = WebMap(item)
    lyrs = [lyr.title for lyr in wm.definition.operationalLayers][::-1]
    self.params[1].filter.list = lyrs
    self.params[1].values = lyrs
    self.previous_webmap_name = current_webmap_name
    break

    return

    def updateMessages(self):
    # Modify the messages created by internal validation for each tool
    # parameter. This method is called after internal validation.
    return

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

    # def postExecute(self):
    # # This method takes place after outputs are processed and
    # # added to the display.
    # return

    1. Hi Chris,
      Great to see you extend this tool. I ran into the same problem when I initially altered the order of the layers, they returned to the original order each time. If you check in my code there is a line to prevent the update after the parameter has been initially altered.

      if not self.params[1].altered:

      Place that line of code as per below…
      if item.title == self.params[0].valueAsText:
      if not self.params[1].altered:
      wm = WebMap(item)

      Let me know how it goes.
      Cheers,
      Glen

Leave a Comment

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