Select to view content in your preferred language

Help with Customizing Legend in Arcpy: White Background, Borders, Hiding Layer Names and Headings

196
6
Jump to solution
Friday
Leo_Unilasalle_2020
Emerging Contributor

Hello everyone,

I’m currently working on automating some map production tasks using Arcpy, and I’m facing a challenge when it comes to customizing the appearance of a legend.

I want to create a legend that has:

  • A white background with borders
  • Hidden layer names and headings

I’ve checked the ESRI documentation, but I can’t seem to find a straightforward way to achieve this using Arcpy. Additionally, I haven’t been able to find information on how to import an existing legend style.

Could anyone guide me on how to customize a legend’s appearance to have a white background and borders and  hide the layer names and headings in the legend, or import a legend style via Arcpy.

Any advice or code examples would be greatly appreciated!

Thanks in advance for your help!

Tags (2)
0 Kudos
1 Solution

Accepted Solutions
AlfredBaldenweck
MVP Regular Contributor

Unfortunately, there isn't a straightforward way; you have to use CIM.

Python CIM access—ArcGIS Pro | Documentation

This is a very useful addin to help you view the CIM and see exactly what you're doing.

Solved: CIM Viewer for ArcPro 3.0 - Esri Community

The biggest problem here is that CIM is absolutely miserable to work with. Granted, I don't work with it frequently, but this took me longer than I'd like to admit to work out.

Anyway, this code gave me a legend with a white background, black border (each with a gap of 5 pts), with no headings or layer names.

aprx = arcpy.mp.ArcGISProject("CURRENT")
lyt= aprx.listLayouts()[0]
lytcim = lyt.getDefinition('V3')
# Grab only the legend elements.
# Probably a more elegant way to do this.
lgds = [e for e in lytcim.elements if "CIMLegend" in str(type(e))]
for lgd in lgds:
    frm = lgd.graphicFrame
    # Set background color
    bckgnd = frm.backgroundSymbol.symbol.symbolLayers[0]
    bckgnd.color = [255,255,255, 255] # Red, Green, Blue, Alpha
    # Set Border color
    brdr = frm.borderSymbol.symbol.symbolLayers[0]
    brdr.color = [0,0,0, 255] # Red, Green, Blue, Alpha
    
    # Add gaps for looks
    frm.backgroundGapX = 5
    frm.backgroundGapY = 5
    frm.borderGapX = 5
    frm.borderGapY = 5
    
    # Iterate through legend items to turn off headings and layer names.
    for item in lgd.items:
        # item.showGroupLayerName = False
        item.showHeading = False
        item.showLayerName = False

#Save changes
lyt.setDefinition(lytcim)

AlfredBaldenweck_0-1736527471552.png

This assumes that you're not getting too fancy with the symbols, so it just works on the first symbol level it finds. That means that if you want your stroke layer to look like this, you're going to have to alter that code a bit.

AlfredBaldenweck_1-1736527677866.png

 

Hope this helps!

 

View solution in original post

6 Replies
TonyAlmeida
MVP Regular Contributor

You could use StyleItem to import an existing legend style?

 

AlfredBaldenweck
MVP Regular Contributor

Oh, this would also work. I've never used this before and didn't think to look haha.

for lgnd in lyt.listElements('LEGEND_ELEMENT'):
    lgnd.applyStyleItem("your styleitemhere")
TonyAlmeida
MVP Regular Contributor

I've never used it before, but I came up with this. One would have to make the .stylx.

 

# Define the path to your project and style file
aprx = arcpy.mp.ArcGISProject("CURRENT")
style_file = r"C:\Path\To\Your\StyleFile.stylx"

# Add the style file to the project
aprx.updateStyles(style_file)

# Get the layout and the legend element
layout = aprx.listLayouts("Your Layout Name")[0]
legend = layout.listElements("LEGEND_ELEMENT", "Your Legend Name")[0]

# List the style items in the style file
style_items = aprx.listStyleItems("LEGEND", style_file)

# Apply the first style item found (you can refine this to select a specific style)
if style_items:
    legend.applyStyleItem(style_items[0])

 

 

Leo_Unilasalle_2020
Emerging Contributor

Thank you very much! I couldn’t get updateStyles to work because I hadn’t added the style file to the project’s style list. So, I made a small change to append it before updating, and it worked! I also realized that when you import a style, it doesn’t exactly match how you saved it (e.g., layer names and headings weren’t hidden).

 

if not style_file in styleItemList:
    styleItemList.append(style_file)
    projet.updateStyles(styleItemList)

 

0 Kudos
AlfredBaldenweck
MVP Regular Contributor

Unfortunately, there isn't a straightforward way; you have to use CIM.

Python CIM access—ArcGIS Pro | Documentation

This is a very useful addin to help you view the CIM and see exactly what you're doing.

Solved: CIM Viewer for ArcPro 3.0 - Esri Community

The biggest problem here is that CIM is absolutely miserable to work with. Granted, I don't work with it frequently, but this took me longer than I'd like to admit to work out.

Anyway, this code gave me a legend with a white background, black border (each with a gap of 5 pts), with no headings or layer names.

aprx = arcpy.mp.ArcGISProject("CURRENT")
lyt= aprx.listLayouts()[0]
lytcim = lyt.getDefinition('V3')
# Grab only the legend elements.
# Probably a more elegant way to do this.
lgds = [e for e in lytcim.elements if "CIMLegend" in str(type(e))]
for lgd in lgds:
    frm = lgd.graphicFrame
    # Set background color
    bckgnd = frm.backgroundSymbol.symbol.symbolLayers[0]
    bckgnd.color = [255,255,255, 255] # Red, Green, Blue, Alpha
    # Set Border color
    brdr = frm.borderSymbol.symbol.symbolLayers[0]
    brdr.color = [0,0,0, 255] # Red, Green, Blue, Alpha
    
    # Add gaps for looks
    frm.backgroundGapX = 5
    frm.backgroundGapY = 5
    frm.borderGapX = 5
    frm.borderGapY = 5
    
    # Iterate through legend items to turn off headings and layer names.
    for item in lgd.items:
        # item.showGroupLayerName = False
        item.showHeading = False
        item.showLayerName = False

#Save changes
lyt.setDefinition(lytcim)

AlfredBaldenweck_0-1736527471552.png

This assumes that you're not getting too fancy with the symbols, so it just works on the first symbol level it finds. That means that if you want your stroke layer to look like this, you're going to have to alter that code a bit.

AlfredBaldenweck_1-1736527677866.png

 

Hope this helps!

 

Leo_Unilasalle_2020
Emerging Contributor

Thank you very much, I heard about CIM but I couldn't figure out how to use it well. This is exactly what I want !
Thank you !