Select to view content in your preferred language

Custom label callout colors using attribute values

815
3
Jump to solution
09-24-2024 02:16 PM
davedoesgis
Frequent Contributor

How can I make the callout background color change with an attribute value, like the screenshot below? The marker icons use a unique values renderer and I want the callout background color to match the icon color. I created this screenshot with SQL-based label classes for each value, but I don't like this solution. I will have 16 unique values, so any small tweak to the label appearance would have to be done 16 times! Is there a way to make the callout background color change based on an attribute? I am comfortable with ArcPy and Arcade if scripting is needed. 

davedoesgis_1-1727199806776.png

I tried Composite Labels, but gave up. It just seemed too complicated, but maybe this is the way to go. 

 

Another idea was to use ArcPy to create label classes. I said above that I don't want SQL-based label classes, but if I can automate it, that takes the pain out of maintaining them. Something like this: 

  • Set up one class of labels the way I want it. Save to .stylx files for the text symbol and label placement. [manual - I may update these over time]
  • Create 16 label classes, each with a SQL clause matching a marker icon. [manual or ArcPy - only need to do this once]
  • Apply the .stylx files (text symbol and label placement) to every class [ArcPy]
  • Set the callout background color specific to each class. [ArcPy]

This doesn't seem super hard, but I have no experience using ArcPy to modify label classes, so any tips there would be great. Thanks!

1 Solution

Accepted Solutions
davedoesgis
Frequent Contributor

I figured it out and it was really simple. The composite callouts that I mentioned are cool, but also unnecessary. It turns out you can use those formatting tags in all kinds of callouts, not just composite style. Here is a better sample that shows how to use them for "Background" style callouts. That sample starts with a very simple static formatting sample. After that, it goes through some code to modify the various elements based on the field value. For a demo, it seems overly complicated, but you'll get the idea if you know Arcade and look at it long enough. The basic idea is you're using code to produce the HTML-like formatting tags for labels. 

Here is a sample I created. I just set up the labels the way I wanted them and then put the formatting tags in the expression. I create 5 color variables and wrote a function to return an opening BGD tag (background) with the color corresponding to a field value. Lastly, I append my opening BGD tag, a name field, and a closing BGD tag. 

davedoesgis_0-1729117251616.png

Here is the documentation on the text formatting tags. If you've ever done any HTML or XML, it's pretty similar. 

Here is the code sample from my expression (from the screenshot above): 

 

var red = [255, 24, 30, 100]
var orange = [255,137, 24, 100]
var yellow = [255, 215, 24, 100]
var green = [0, 172, 58, 100]
var other = [156, 156, 156, 100]

function SetBackgroundColor(sector) {
  var color = other;
  if (sector == 'Destroyed') {color = red}
  if (sector == 'Failed') {color = orange}
  if (sector == 'Damaged') {color = yellow}
  if (sector == 'No Damage') {color = green}
  return `<BGD red='${color[0]}' green='${color[1]}' blue='${color[2]}' alpha='${color[3]}'>`
}

SetBackgroundColor($feature.type) + $feature.name + "</BGD>"

 

 

One last note: On the Composite style callouts, the background was just applied to the text, but not the margin/padding area. It was more like the highlighter tool in Word than cell shading of the 3x3 grid. The Composite style callout is cool functionality and I hope to actually use it someday, but the background color didn't feel like it was fully working. If anyone knows more getting this to work, please reply. 

davedoesgis_1-1729117599794.png

 

 

View solution in original post

0 Kudos
3 Replies
davedoesgis
Frequent Contributor

I figured it out and it was really simple. The composite callouts that I mentioned are cool, but also unnecessary. It turns out you can use those formatting tags in all kinds of callouts, not just composite style. Here is a better sample that shows how to use them for "Background" style callouts. That sample starts with a very simple static formatting sample. After that, it goes through some code to modify the various elements based on the field value. For a demo, it seems overly complicated, but you'll get the idea if you know Arcade and look at it long enough. The basic idea is you're using code to produce the HTML-like formatting tags for labels. 

Here is a sample I created. I just set up the labels the way I wanted them and then put the formatting tags in the expression. I create 5 color variables and wrote a function to return an opening BGD tag (background) with the color corresponding to a field value. Lastly, I append my opening BGD tag, a name field, and a closing BGD tag. 

davedoesgis_0-1729117251616.png

Here is the documentation on the text formatting tags. If you've ever done any HTML or XML, it's pretty similar. 

Here is the code sample from my expression (from the screenshot above): 

 

var red = [255, 24, 30, 100]
var orange = [255,137, 24, 100]
var yellow = [255, 215, 24, 100]
var green = [0, 172, 58, 100]
var other = [156, 156, 156, 100]

function SetBackgroundColor(sector) {
  var color = other;
  if (sector == 'Destroyed') {color = red}
  if (sector == 'Failed') {color = orange}
  if (sector == 'Damaged') {color = yellow}
  if (sector == 'No Damage') {color = green}
  return `<BGD red='${color[0]}' green='${color[1]}' blue='${color[2]}' alpha='${color[3]}'>`
}

SetBackgroundColor($feature.type) + $feature.name + "</BGD>"

 

 

One last note: On the Composite style callouts, the background was just applied to the text, but not the margin/padding area. It was more like the highlighter tool in Word than cell shading of the 3x3 grid. The Composite style callout is cool functionality and I hope to actually use it someday, but the background color didn't feel like it was fully working. If anyone knows more getting this to work, please reply. 

davedoesgis_1-1729117599794.png

 

 

0 Kudos
davedoesgis
Frequent Contributor

Hopefully my last comment on this... Note that there is striping on the text when it spans multiple lines. 

davedoesgis_0-1729199554064.png

My label background was a very light yellow before I applied the BGD tag to it, and that is the color you're seeing in the stripes. I think this is the same issue I pointed out with the composite labels in that the BGD tag is acting more like a text highlighter tool than a cell background shading. Fortunately, the background is covering the whole width of the callout, but annoying that it just covers the height of the text. Here it is if I set the line spacing to 3 to illustrate the exaggerated effect: 

davedoesgis_1-1729199655000.png

I can fix this, but it's annoying to have to lose other functionality: 

davedoesgis_2-1729203689761.png

My take-away from fiddling with these formatting tags is that they aren't fully baked and Esri needs to work on them some more. That's especially true for the background tag, which has been a pretty frustrating experience. 

0 Kudos
davedoesgis
Frequent Contributor

In the original post, I speculated that creating unique label classes was the way to go, but only if it could be automated. This solution might be useful if you're trying to build up sharable symbol sets (a .stylx file), but I think the accepted solution on this post is easier.

For this to be useful, I was thinking of a workflow like this:

  • Loop through the unique field values. For each one:
    • Create a new label class
    • Copy the style from a template label class
    • Set its SQL query
    • Set its background color

This documentation page shows how to create a new label class and set its SQL query in ArcPy. I'm guessing the new label class created would just have default properties, so I'd have to figure out how to update them. You can apply a style from a .stylx file from the ribbon in Pro, but I don't know how in ArcPy. More on this later. 

To set the background color for a label class, you have to go down multiple rabbit holes. Here is path in the object model to find the background color: APRX document >> maps[] >> layers[] >> CIM (via layer.getDefinition) >> labelClasses[] >> textSymbol >> symbol >> callout >> backgroundSymbol >> symbolLayers[] >> color >> values. 

Values is a list you can set like this: [red, green, blue, alpha/opacity]. See the attached PDF for a code sample. You can see me drilling down into all of these and querying them. Using a Python IDE with breakpoints and variable inspection would've been easier than this, but it works. 

With the link above and this sample code, I have everything I need, except a way to clone the rest of the label properties when the new label class is created. You can apply a label style manually from the label ribbon, but I don't know how in ArcPy (please tell me if I'm wrong!). That said, if you have a template label class, maybe you could copy its "textSymbol" property (see above) and apply it to the newly created label class? Then, you could set your background color. 

Anyhow, I spent a bunch of time on this and wanted to post it for the group before going in another direction. Maybe it's useful to someone else? I hope Esri will add ArcPy functionality to apply label class styles from .stylx files.

Notes:

 

 

 

0 Kudos