Hello everyone, I have created a label class to display labels for my feature layer.
However, the default label style is not ideal, and I want to customize the font, size, color, and other properties.
I noticed that the LabelClass object does not have a symbol attribute. https://pro.arcgis.com/en/pro-app/3.4/arcpy/mapping/labelclass-class.htm
Could someone advise how I can achieve this using ArcPy (ArcGIS Pro 3.4)? I have searched various platforms but haven’t found a solution.
# Enable layer labels but toggle off all existing label classes
layer.showLabels = True
for lc_old in layer.listLabelClasses():
lc_old.visible = False
# Create a new Label class and toggle it on
lc_new = layer.createLabelClass(name = 'School Name - Python',
expression = '[NAME]',
labelclass_language = 'Python')
lc_new.visible = True
Solved! Go to Solution.
Okay, I had some more time to look at this.
#Get layer
aprx = arcpy.mp.ArcGISProject("CURRENT")
mp = aprx.activeMap
lay = mp.listLayers("label")[0]
# Get definition
laycim = lay.getDefinition("V3")
# For each label class, do the following
for lc in laycim.labelClasses:
sym = lc.textSymbol.symbol
# Change font size and style
sym.fontFamilyName = "Arial"
sym.fontStyleName = "Bold"
sym.height = 25
# Change the fill to red
fill = sym.symbol.symbolLayers[0]
fill.color.values = [255,0,0,255] # Turn it red and opague
# Add an outline
outline = arcpy.cim.CIMSymbols.CIMSolidStroke()
outline.color = [0,100,255,255] #idk what color this is.
outline.width = 2
# Overwrite current symbol with the fill and the outline
sym.symbol.symbolLayers= [fill, outline]
# Apply the new label symbols
lay.setDefinition(laycim)
This didn't take me too long, but it wasn't fun.
What you aren't seeing is liberal use of print(dir(variable)) to determine what I had, e.g. for the colors
Steps I took:
All this to say it's a lot of work and trial and error to get what you want and you might have a much easier time applying properties from another layer. CIM is awful and should be avoided if you can.
Thank you @AlfredBaldenweck so much. I have applied your script and solved the labeling properties issue. I can change the font, color, and size of the labels using ArcPy.
import arcpy
# Get layer
aprx = arcpy.mp.ArcGISProject("CURRENT")
mp = aprx.activeMap
lay = mp.listLayers("Ottawa_Census")[0]
# Enable labeling and turn off old label classes
lay.showLabels = True
for lc_old in lay.listLabelClasses():
lc_old.visible = False
print('Old labels turned off')
# Create new label class
lay.createLabelClass(name='Label - Python',
expression='[DACODE]',
sql_query="POP_2016 >= 1000",
labelclass_language='Python')
print('New label class created')
# Placed after creating the new label class
laycim = lay.getDefinition("V3")
# Change the label style
for lc in laycim.labelClasses:
if lc.name == 'Label - Python':
sym = lc.textSymbol.symbol
sym.fontFamilyName = "Cambria"
sym.fontStyleName = "Bold"
sym.height = 8
# Set the fill color
fill = sym.symbol.symbolLayers[0]
fill.color.values = [255, 0, 0, 255] # red
# Set the outline color and width
outline = arcpy.cim.CIMSolidStroke()
outline.color = [0, 100, 255, 255] # blue
outline.width = 1.5
# Apply the new style
sym.symbol.symbolLayers = [fill, outline]
# Apply the new defintion
lay.setDefinition(laycim)
print('Label class style updated and applied')
I think it's as simple as running an `aprx.save()` after you finish.
# Enable layer labels but toggle off all existing label classes
aprx = arcpy.mp.ArcGISProject("CURRENT")
layer.showLabels = True
for lc_old in layer.listLabelClasses():
lc_old.visible = False
# Create a new Label class and toggle it on
lc_new = layer.createLabelClass(name = 'School Name - Python',
expression = '[NAME]',
labelclass_language = 'Python')
lc_new.visible = True
aprx.save()
Simply adding aprx.save() doesn't help. I want to change the font, size, color of labels.
Ah, in that case Alfred is correct. You'll have to do CIM editing. The Python API is awful, but you can do it. Here's a little starter with a re-implemented LabelClass CIM def with proper type hinting:
from arcpy.cim import CIMSymbolReference
from arcpy.cim.CIMLabelPlacement import (
CIMLabelClass,
CIMMaplexGeneralPlacementProperties,
CIMStandardLabelPlacementProperties,
)
from arcpy.cim import (
LabelExpressionEngine,
FeaturesToLabel,
)
class CIMLabelClass():
"""
Represents a label class which describes how to generate a set
of text labels from a group of features in a feature layer.
"""
def __init__(self, *args, **Kwargs):
self.expressionTitle: str = ''
self.expression: str = ''
self.expressionEngine: LabelExpressionEngine = LabelExpressionEngine.VBScript
self.featuresToLabel: FeaturesToLabel = FeaturesToLabel.AllVisibleFeatures
self.maplexLabelPlacementProperties: CIMMaplexGeneralPlacementProperties = CIMMaplexGeneralPlacementProperties()
self.maximumScale: float = 0.0
self.minimumScale: float = 0.0
self.name: str = ''
self.priority: int = -1
self.standardLabelPlacementProperties: CIMStandardLabelPlacementProperties = CIMStandardLabelPlacementProperties()
self.textSymbol: CIMSymbolReference = CIMSymbolReference()
self.useCodedValue: bool = True
self.whereClause: str = ''
self.visibility: bool = False
self.iD: int = -1
aprx = arcpy.mp.ArcGISProject(r'path/to/project')
_map = [m for m in aprx.listMaps() if m.name == 'Map Name'][0]
lay = [l for l in _map.listLayers() if l.name == 'Layer Name'][0]
label = lay.listLabelClasses()[0]
label_def: CIMLabelClass = label.getDefinition('V3')
label_def.expressionEngine = LabelExpressionEngine.Python
label_def.expression = "[Name]"
label_def.name = 'My Label Class'
...
aprx.save()
Look into CIM, but beware it suuuuuucks.
Okay, I had some more time to look at this.
#Get layer
aprx = arcpy.mp.ArcGISProject("CURRENT")
mp = aprx.activeMap
lay = mp.listLayers("label")[0]
# Get definition
laycim = lay.getDefinition("V3")
# For each label class, do the following
for lc in laycim.labelClasses:
sym = lc.textSymbol.symbol
# Change font size and style
sym.fontFamilyName = "Arial"
sym.fontStyleName = "Bold"
sym.height = 25
# Change the fill to red
fill = sym.symbol.symbolLayers[0]
fill.color.values = [255,0,0,255] # Turn it red and opague
# Add an outline
outline = arcpy.cim.CIMSymbols.CIMSolidStroke()
outline.color = [0,100,255,255] #idk what color this is.
outline.width = 2
# Overwrite current symbol with the fill and the outline
sym.symbol.symbolLayers= [fill, outline]
# Apply the new label symbols
lay.setDefinition(laycim)
This didn't take me too long, but it wasn't fun.
What you aren't seeing is liberal use of print(dir(variable)) to determine what I had, e.g. for the colors
Steps I took:
All this to say it's a lot of work and trial and error to get what you want and you might have a much easier time applying properties from another layer. CIM is awful and should be avoided if you can.
hu, I had a crack at layer styles a couple years back and was only able to get as far as unique values, when I tried doing stuff like hatching I ran into a wall and didn't really know how to progress but having knowledge that CIM exists in my back pocket if I touch it again will be useful.
I use a combination of the documentation linked above and the Python Window in Pro because it has intellisense
It's not actually intelisense, terrifyingly it's actually passing the contents of the REPL box to some metafunctions that live in the arcpy.utils module.
All they do is reformat the docstring with XML tags and such. It also traverses the stack frame looking for variables defined in scope.
It's worth a read:
Thank you @AlfredBaldenweck so much. I have applied your script and solved the labeling properties issue. I can change the font, color, and size of the labels using ArcPy.
import arcpy
# Get layer
aprx = arcpy.mp.ArcGISProject("CURRENT")
mp = aprx.activeMap
lay = mp.listLayers("Ottawa_Census")[0]
# Enable labeling and turn off old label classes
lay.showLabels = True
for lc_old in lay.listLabelClasses():
lc_old.visible = False
print('Old labels turned off')
# Create new label class
lay.createLabelClass(name='Label - Python',
expression='[DACODE]',
sql_query="POP_2016 >= 1000",
labelclass_language='Python')
print('New label class created')
# Placed after creating the new label class
laycim = lay.getDefinition("V3")
# Change the label style
for lc in laycim.labelClasses:
if lc.name == 'Label - Python':
sym = lc.textSymbol.symbol
sym.fontFamilyName = "Cambria"
sym.fontStyleName = "Bold"
sym.height = 8
# Set the fill color
fill = sym.symbol.symbolLayers[0]
fill.color.values = [255, 0, 0, 255] # red
# Set the outline color and width
outline = arcpy.cim.CIMSolidStroke()
outline.color = [0, 100, 255, 255] # blue
outline.width = 1.5
# Apply the new style
sym.symbol.symbolLayers = [fill, outline]
# Apply the new defintion
lay.setDefinition(laycim)
print('Label class style updated and applied')