Enable and set Feature Layer search capabilities in an ArcGIS Online WebMap using 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 components of ArcGIS Online such as WebMap functionality. In this post we will focus on adding Feature Layer search capabilities within the WebMap using teh ArcGIS API for Python.

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.

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. We also require the FeatureLayer class from the features module to access field information for the layers of our WebMap.

				
					## import GIS which provides the gateway entry to your AGOL
from arcgis.gis import GIS

## import the WebMap class to provide for interacting with WebMap layers
from arcgis.mapping import WebMap

## import the FeatureLayer class to get field information
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 WebMap Object

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)
				
			

Prepare the Search configurations for each layer

We will see in the next section, that the “layers” property for the search application is a list, and it is a list of dictionaries.

Each dictionary contains an “id” key, which represents the id of the layer in the WebMap. We can obtain this “id” from the operationalLayers information for each layer.

Each dictionary also contains a “field” key, which has a dictionary value containing “name” (field name), “exactMatch” (we’ll set this to False so that the use does not have to enter the full search value), and “type” (field datatype – we are interested in Strings and Integers in this example).

I know my data and I know the I want Strings and Integer fields, you may only want Strings or you might know the exact field names you want to add to the search. You can alter the code here to suit your requirements.

Iterate through the layers in the WebMap and create a search entry for each field that matches the criteria.

				
					## store a list of dictionaries, each dictionary will define the search for
## a field in a layer
search_layers = []

## iterate through the WebMap layers
for layer in webmap.definition.operationalLayers:
    ## create a FeatureLayer object
    fl = FeatureLayer(
        url = layer["url"],
        gis = agol
    )

    ## iterate through the fields for the Feature Layer
    for fld in fl.properties.fields:
        ## if there are text of integer fields
        if fld["type"] in ["esriFieldTypeString", "esriFieldTypeInteger"]:
            ## create an entry for the search_layers list
            search_dict = {
                "id" : layer["id"],
                "field" : {
                    "name" : fld["name"],
                    "exactMatch": False,
                    "type" : fld["type"]
                }
            }
            ## add the dictionary to the list
            search_layers.append(search_dict)
				
			

Alter the JSON to reflect the Search capabilities

A WebMap object can have an “applicationProperties” property in its definition. It is in here we want to add the properties that define our Search capabilities. 

The search variable below, which is a dictionary, defines the Search capabilities for the WebMap. We set “enabled” to True, and the “layers” to the list of dictionaries we created in the previous section.

If there are currently no applications set on the WebMap then the “applicationProperties” property will more than likely not exists, and if so, we can add it ourselves and we will also make sure there is a “viewing” property within the “applicationProperties”.

It is to this “viewing” property that we want to add our Search definition.

				
					## this is the JSON for the search capability with a WebMap
search = {
    "enabled": True,
    "disablePlaceFinder": False,
    "hintText": "Search Here...",
    "layers": search_layers,
    "tables": []
}

## search is added to the viewing property of the applicationProperties property
## check if the applicationProperties currently exists and if it does not,
## define the property
if "applicationProperties" not in webmap.definition:
    webmap.definition["applicationProperties"] = {"viewing" : {}}

## set the search property, within the viewing property to our search definition
## above
webmap.definition["applicationProperties"]["viewing"]["search"] = search
				
			

Update and Save the WebMap (item)

Because we have directly manipulated the JSON, we need to update the Item object that represents the WebMap and not the WebMap object itself. See the WebMap object versus WebMap Item blog post for more information on that!

				
					item_properties = {"text":webmap.definition}

status = wm_item.update(
    item_properties=item_properties
)

print(status)

				
			

Tip!

Add the search parameters manually and print the JSON to screen via the WebMap object definition property to see how the JSON is constructed.

Before and After Running the Script

Before

WebMap layer search Application Settings without Layer searching enabled
Search panel in ArcGIS Online WebMap without Layer search set

After

ArcGIS Online WebMap layer search Application Setting with layer search enabled
ArcGIS Online WebMap search with layer search added

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.

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.

				
					## import GIS which provides the gateway entry to your AGOL
from arcgis.gis import GIS

## import the WebMap class to provide for interacting with WebMap layers
from arcgis.mapping import WebMap

## import the FeatureLayer class to get field information
from arcgis.features import FeatureLayer

################################################################################
## API Reference Links:
## https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#gis
## https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#arcgis.gis.ContentManager.get
## https://developers.arcgis.com/python/api-reference/arcgis.mapping.toc.html#webmap
## https://developers.arcgis.com/python/api-reference/arcgis.features.toc.html#featurelayer
## https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#item
## https://developers.arcgis.com/python/api-reference/arcgis.gis.toc.html#arcgis.gis.Item.update
##
## API Version: 2.1.0.2, 2.2.0.1, 2.3.0
##
################################################################################

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

## Access the WebMap Item
wm_item = agol.content.get("WM_ITEM_ID")

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

################################################################################
## CREATE SEARCH LAYERS DICTIONARIES ###########################################

## store a list of dictionaries, each dictionary will define the search for
## a field in a layer
search_layers = []

## iterate through the WebMap layers
for layer in webmap.definition.operationalLayers:
    ## create a FeatureLayer object
    fl = FeatureLayer(
        url = layer["url"],
        gis = agol
    )

    ## iterate through the fields for the Feature Layer
    for fld in fl.properties.fields:
        ## if there are text of integer fields
        if fld["type"] in ["esriFieldTypeString", "esriFieldTypeInteger"]:
            ## create an entry for the search_layers list
            search_dict = {
                "id" : layer["id"],
                "field" : {
                    "name" : fld["name"],
                    "exactMatch": False,
                    "type" : fld["type"]
                }
            }
            ## add the dictionary to the list
            search_layers.append(search_dict)


################################################################################
## MANIPULATE THE WEBMAP JSON ##################################################

## this is the JSON for the search capability with a WebMap
search = {
    "enabled": True,
    "disablePlaceFinder": False,
    "hintText": "Search Here...",
    "layers": search_layers,
    "tables": []
}

## search is added to the viewing property of the applicationProperties property
## check if the applicationProperties currently exists and if it does not,
## define the property
if "applicationProperties" not in webmap.definition:
    webmap.definition["applicationProperties"] = {"viewing" : {}}

## set the search property, within the viewing property to our search definition
## above
webmap.definition["applicationProperties"]["viewing"]["search"] = search

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

item_properties = {"text":webmap.definition}

status = wm_item.update(
    item_properties=item_properties
)

print(status)

################################################################################
print("\nSCRIPT COMPLETE")
				
			

Leave a Comment

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