Select to view content in your preferred language

Label Features in ArcGIS Online Web Maps Using the ArcGIS API for Python | Step-by-Step Guide

86
0
yesterday
Clubdebambos
MVP Regular Contributor
3 0 86

 

The ArcGIS API for Python version 2.4 introduced the Map class as a replacement for the WebMap class from previous versions. The Map class has a property called content that is the MapContent class that aids with accessing, managing, and updating components of WebMap layers and tables. The update_layer() method is at the heart of being able to update layers for various elements such as symbology (renederer), forms, transparency, layer titles, and labelling amongst others. Unfortunately, as of writing this article (v2.4.1.1), updating the labels has a bug. But that can't stop us from updating labels for a layer via the WebMap definition. 

The video above explores the current bug with the update_layer(label_info) parameter and how we can use the Item object get_data() method to access the WebMap definition as a Python dictionary, manipulate the labelingInfo property for a layer and ultimately update labels in a WebMap. 

The labelingInfo property is a list that can contain dictionaries that represent a label class for a layer in a WebMap. We will look at the minimum viable label class properties required as shown below.

label_info = [
    {
        "labelExpression": "[COUNTY]", # only used if labelExpressionInfo is missing
        "symbol": {
            "type": "esriTS",
            "color": [
                0,
                0,
                0,
                255
            ]
        }
    }
]

 

We will build upon this minimum definition to manipulate labels for a layer relating to:

  • Arcade Expressions
  • Fonts (family, size, weight, style)
  • Halo
  • Angle
  • Offsets
  • Background
  • Scale Range
  • Filtering

The WebMap Specification is an excellent resource for finding out what properties are available for labels. For example, in the ArcGIS Online GUI we cannot set a label angle or underline text, but we can set these with code. We must also note that we cannot use all the properties that are listed in the specification, some simply do not work, but I implore you to test them out. These properties could be signs of what is to come, and they probably work if you're building a WebMap with the JavaScript SDK for ArcGIS.

Here is the code from the video with some helpful comments.

from arcgis.gis import GIS

################################################################################
## 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.gis.toc.html#item
##  https://developers.arcgis.com/python/latest/api-reference/arcgis.gis.toc.html#arcgis.gis.Item.get_data
##  https://developers.arcgis.com/web-map-specification/objects/labelingInfo/
##
################################################################################

## Access ArcGIS Online
agol = GIS("home")

## get the WebMap content item as an Item object
wm_item = agol.content.get("WM_ITEMID")

################################################################################
## labelingInfo definition
################################################################################

label_info = [
    {
        "name" : "County Names", # the name of the label class
        "labelExpression": "[COUNTY]", # only used if labelExpressionInfo is missing
##        "labelExpressionInfo": {
##            "expression": "$feature[\"COUNTY\"]",
##        },
        "labelExpressionInfo": {
            "expression": "\"Co. \" + Proper($feature[\"COUNTY\"])", # arcade expression
            "title" : "Co. Expression" # the name/title of the expression
        },
        "symbol": {
            "type": "esriTS", # the only type available - Esri Text Symbol
            "color": [
                0, # R
                0, # G
                0, # B
                255 # Alpha (transparency)
            ],
            "font": {
                "family": "Arial",
                "size": 12, # size is in points
                "weight" : "bold", # bold, bolder, lighter, normal
                "style" : "italic", # italic, normal, oblique
                "decoration" : "underline" # line-through, none, underline
            },
            "haloColor": [
                255,
                255,
                0,
                255
            ],
            "haloSize": 1,
            "angle": 45, # East and counter-clockwise
            "xoffset": 50, # in points
            "yoffset": 50, # in points
            "backgroundColor" : [ # adds coloured rectangle the lable
                0,
                0,
                0,
                255
            ],
            "borderLineColor" : [ # adds an outline colour to the backgroundColor
                255,
                255,
                0,
                255
            ],
            "borderLineSize" : 1
        },
        "maxScale" : 100000, # scale range
        "minScale" : 10000000, # scale range
        "where" : "PROVINCE = 'Leinster'" # filter
    }
]

################################################################################
## Applying the labels
################################################################################

## get the WebMap definition as a Python Dictionary
wm_item_data = wm_item.get_data()

## for each layer definition (dict) in the operationalLayers (list)
for lyr_def in wm_item_data["operationalLayers"]:

    ## if the title of the layer matches where we want to update/apply labels
    if lyr_def["title"] == "County Boundaries":

        ## display the labels
        lyr_def["showLabels"] = True

        ## set the labelingInfo ################################################

        ## check if layerDefinition exists in the layer properties
        if "layerDefinition" in lyr_def:
            ## if it does, then check for a drawingInfo property
            if "drawingInfo" in lyr_def["layerDefinition"]:
                ## update labelingInfo property if drawingInfo exists
                lyr_def["layerDefinition"]["drawingInfo"]["labelingInfo"] = label_info
            ## otherwise create the draingInfo property and the labelingInfo
            else:
                lyr_def["layerDefinition"]["drawingInfo"] = {"labelingInfo" : label_info}
        ## if not, create the properties
        else:
            lyr_def["layerDefinition"] = {"drawingInfo" : {"labelingInfo" : label_info}}

## update the WebMap Definition with the altered layer properties
wm_item.update(
    item_properties = {"text" : wm_item_data}
)

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

 

Contributors
About the Author
Glen Bambrick is GIS Consultant with extensive experience utilising skills for GIS project management, quality map production, data management, geospatial analysis, standardisation, and workflow automation across a range of industries such as agriculture, oil & gas, telecommunications and engineering. Going beyond map production there is a passion for the technologies behind GIS, the databases, the programming languages, the analysis and statistical output, and continued professional development associated with GIS. You will mainly find me contributing in the Python and ArcGIS API for Python Communities.