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:
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!
Solved! Go to Solution.
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)
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.
Hope this helps!
You could use StyleItem to import an existing legend style?
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")
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])
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)
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)
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.
Hope this helps!
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 !