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.

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