Hello everyone,
I’m working on automating the legend, but I keep encountering formatting issues. My goal is to position the legend to the right of the map and have it displayed vertically from top to bottom. Since the number of legend items can vary, the legend height should not be a fixed value.
In lines 47 and 48, I limit the legend to a single column and set it to adjust the font size automatically. Additionally, I ensure sufficient vertical space by setting the legend height to 15 (line 34). However, as shown in the attached image, the legend gets cut off at a certain point.
The issue is not with the symbols but rather with the legend formatting, which I haven't been able to resolve. I also attempted to set the fittingStrategy (line 47) to 'AdjustColumnsAndFont' and commented out columnCount (line 48), but this caused the legend to be cut off horizontally instead.
I've attached examples below for reference. Any insights or suggestions would be greatly appreciated!
def MakeRec_LL(llx, lly, w, h):
xyRecList = [
[llx, lly],
[llx, lly + h],
[llx + w, lly + h],
[llx + w, lly],
[llx, lly]
]
array = arcpy.Array([arcpy.Point(*coords) for coords in xyRecList])
return arcpy.Polygon(array)
def mapLayout(m_title):
p = arcpy.mp.ArcGISProject(new_aprx_path)
lyt = p.createLayout(17, 11, 'INCH')
m = p.listMaps("Map")[0]
# Map Frame Configuration
map_frame_width, map_frame_height = 13, 7.5
map_frame_x = ((17 - map_frame_width) / 2) - 1.5
map_frame_y = (11 - map_frame_height) / 2
mf = lyt.createMapFrame(
MakeRec_LL(map_frame_x, map_frame_y, map_frame_width, map_frame_height),
m,
"New Map Frame"
)
lyt = p.listLayouts('Layout')[0]
mf = lyt.listElements('MAPFRAME_ELEMENT', 'New Map Frame')[0]
# Legend Configuration
legend_x = 13.5 # Adjusted X position
legend_y = 8 # Lower starting Y position
legend_width = 3 # Narrow width
legend_height = 15 # Increased height to allow vertical expansion
# Define the legend style
legend_style = p.listStyleItems('ArcGIS 2D', 'LEGEND', 'Legend 1')[0]
# Create the legend
legend = lyt.createMapSurroundElement(
arcpy.Point(legend_x, legend_y), 'LEGEND', mf, legend_style, 'Map Legend'
)
# Configure legend appearance and behavior
legend.elementWidth = legend_width
legend.elementHeight = legend_height
legend.fittingStrategy = 'AdjustFontSize'
legend.columnCount = 1 # Force single column (vertical)
legend.showTitle = False
# Valid categories to display in the legend
valid_categories_in_map = [
"Damage or destruction, looting, or theft of cultural heritage",
"Damage or destruction of civilian critical infrastructure",
"Enslavement",
"Extrajudicial killing",
"Forced disappearance",
"Gender-based or other conflict-related sexual violence",
"Human trafficking",
"Indiscriminate use of weapons",
"Kidnapping",
"Mass execution",
"Military operations (battle, shelling)",
"Movement of military, paramilitary, or other troops and equipment",
"Persecution based on political, racial, ethnic, gender, or sexual orientation",
"Torture or indications of torture",
"Unlawful detention",
"Violent crackdowns on protesters/opponents/civil rights abuse",
"Willful killing of civilians"
]
# Use CIM to refine the legend further
lyt_cim = lyt.getDefinition('V3')
for elm in lyt_cim.elements:
if elm.name == "Map Legend":
legend_cim = elm
# Remove the background frame/outline
legend_cim.frame = None
# Customize text properties
for item in legend_cim.items:
item.showHeading = False
item.showLabels = False
# Adjust text symbol properties if possible
if hasattr(item, 'textSymbol'):
item.textSymbol.fontSize = 7 # Slightly larger for readability
item.textSymbol.fontFamily = 'Arial'
item.textSymbol.fontStyle = 'Regular'
# Update the definition
lyt.setDefinition(lyt_cim)
# Filter legend items
for item in legend.items[:]: # Create a copy of the list to safely modify
try:
if item.name not in valid_categories_in_map:
legend.removeItem(item)
except Exception as e:
print(f"Error processing legend item {item}: {e}")
# Debug information
print(f"Total legend items after filtering: {len(legend.items)}")
for item in legend.items:
print(f"Remaining legend item: {item.name}")
# Finalize legend positioning
legend.elementPositionX = legend_x
legend.elementPositionY = legend_y
remaining code...