Select to view content in your preferred language

Working Example: Apply UniqueValueRenderer with Picture Marker Symbols Using arcpy in ArcGIS Pro

173
0
Tuesday
Samy_BoumaNgock
Emerging Contributor
0 0 173

Hi everyone,

I’m sharing a working Python script that applies a UniqueValueRenderer symbology to a point feature class in ArcGIS Pro using arcpy. This implementation uses Picture Marker Symbols to represent each unique value in a field—specifically, country flags. The shared code is part of a broader implementation.

SamyBouma_Ngock_0-1748357457635.gif

Why This Matters

Many of us have faced challenges when working with CIM-based symbology in ArcGIS Pro. The documentation around the Cartographic Information Model (CIM) can be sparse or unclear, and issues often arise regardless of the programming language used.

This post aims to provide a working example that others can adapt and build upon.

 

Use Case

  • Feature class type: Point (e.g., country centroids)
  • Field used for symbology: Country_Flag
    • Must use the internal field name, not the alias
    • Field name is case-sensitive
  • Unique values: 238 (each representing a country)
  • Goal: Assign a Picture Marker Symbol (flag image) to each point based on the Country_Flag field

 

Implementation Steps

  • Set a default UniqueValueRenderer using a basic shape marker, keyed on the Country_Flag field.
  • Iterate through each unique value and assign a Picture Marker Symbol using images stored in a local folder.
    • Each image filename matches a value in the Country_Flag field exactly (e.g., France.png, Brazil.png).

 

Key Challenges

  • CIM complexity: The structure of CIM symbol layers is not always intuitive.
  • Field name sensitivity: Using the alias or incorrect casing can silently fail.
  • Lack of consistent examples: Many developers report inconsistent behavior or undocumented quirks when applying symbology programmatically.

 

Why I’m Posting

I’ve seen many threads where people are stuck on similar issues, so I wanted to contribute a working reference. If you're trying to automate symbology in ArcGIS Pro using arcpy, this might save you some time.

In the code below, read "data:image" in its HTML version data+colon symbol+image

Cheers,

    def set_defaultuniquevaluesrenderer(featurelayer=None, fieldname=None):
        """Set a default unique values renderer for the specified field in the feature layer."""
        if featurelayer is None:
            arcpy.AddError("Layer not found. Symbology not updated.")
        
        sym = featurelayer.symbology
        sym.updateRenderer('UniqueValueRenderer')
        sym.renderer.fields = [fieldname]
        featurelayer.symbology = sym
        arcpy.AddMessage(f"Symbology updated to UniqueValueRenderer on field: {fieldname}")

    def set_updatesymbology(featurelayer=None, fieldname=None, imagefolder=None):
        """Update only the point symbols as picture markers with corresponding images."""
        if featurelayer is None:
            arcpy.AddError("Layer not found. Symbology not updated.")

        # Get the CIM (Cartographic Information Model) definition of the layer
        cim = featurelayer.getDefinition('V3')
        renderer = cim.renderer

        # Iterate through each class in the renderer's first group
        for classDef in renderer.groups[0].classes:
            # Get the value for the symbol (usually the flag image filename)
            try:
                value = classDef.values[0].fieldValues[0]
            except (AttributeError, IndexError, TypeError):
                arcpy.AddWarning(f"Skipping class with no valid value for symbol: {classDef.name}")
                continue
            
            # Build the full path to the image file
            imagePath = os.path.join(imagefolder, value)
            if arcpy.Exists(imagePath):
                # Read and encode the image as base64
                with open(imagePath, "rb") as imgFile:
                    encoded = base64.b64encode(imgFile.read()).decode("utf-8")
                # Define a CIMPictureMarker using the encoded image
                pictureMarker = {
                    "type": "CIMPictureMarker",
                    "enable": True,
                    "size": 10,
                    "url": f"data:image/png;base64,{encoded}",
                }
                # Create a CIMPointSymbol with the picture marker
                pointSymbol = {
                    "type": "CIMPointSymbol",
                    "symbolLayers": [pictureMarker]
                }
                # Create a CIMSymbolReference for the class symbol
                symbolRef = {
                    "type": "CIMSymbolReference",
                    "symbol": pointSymbol
                }
                # Assign the new symbol to the class definition
                classDef.symbol = symbolRef

        # Apply the updated CIM definition back to the feature layer
        featurelayer.setDefinition(cim)
        arcpy.AddMessage("Point symbols updated with corresponding flag images.")

 

Labels