Mapping a CSS gradient based on numerical or percentage scale

Suppose I have this gradient:

linear-gradient(green, yellow, red)

I'd like to map color values from the gradient on a percentage basis... 100% would be pure green, 50% would be pure yellow, 0% would be pure red. The percent value exists somewhere easily accessible by an expression or script, like a custom property or a label component.

I want to be able to output (or bind) 1 singular color (NOT a gradient, but rather 1 color pulled out of the gradient) at any given moment of time corresponding to the percentage value. Is there an easy way to do this? If my percentage were, say, 25%, I'd like the color output to be halfway between red and yellow (i.e. orange). Maybe there is a Python function or expression function that can do this?

def interpolate_color(color1, color2, factor):
    """Interpolate between two colors."""
    # Generate a color by linearly interpolating between two colors based on the factor (0 to 1)
    return tuple(int(c1 + (c2 - c1) * factor) for c1, c2 in zip(color1, color2))

def get_color_from_gradient(percentage):
    # Define RGB colors for green, yellow, and red
    green = (0, 255, 0)
    yellow = (255, 255, 0)
    red = (255, 0, 0)

    if percentage >= 50:
        # Interpolate between green and yellow
        # Map the percentage from range 100-50 to 0-1
        factor = (percentage - 50) / 50.0
        return interpolate_color(yellow, green, factor)
    else:
        # Interpolate between yellow and red
        # Map the percentage from range 50-0 to 0-1
        factor = percentage / 50.0
        return interpolate_color(red, yellow, factor)

def color_to_hex(color):
    """Convert an RGB tuple to a hexadecimal string."""
    return '#%02x%02x%02x' % color

# Example usage
percentage = 25  # You can replace this value with any percentage
color_at_percentage = get_color_from_gradient(percentage)
hex_color = color_to_hex(color_at_percentage)
print("Color at {}% is {}".format(percentage, hex_color))

This should get you most of the way

1 Like

I'm not proud of this, but it it's an expression which will perform better than a script and works for red, yellow, green. Add the script below into an expression binding on the component background.

RYG background indicator

Note that the hex colors go from

red    #FF0000
yellow #FFFF00
green  #00FF00

so most of the expression is trying to handle the "both on" in the middle.

Background expression binding
"#" 
+ right("0" 		// Red
	+ toHex(
		if(
			{../Slider.props.value} < 50, 
			255,
			256 - ({../Slider.props.value} - 50) * 5.11
		)
	)
, 2)
+ right("0" 		// Green
	+ toHex(
		if(
			{../Slider.props.value} < 50, 
			({../Slider.props.value} - 50) * 5.11,
			255
		)
	)
, 2)
+ "00"				// Blue

Please think carefully about why you're doing this. Color can introduce a lot of visual clutter. See High Performance HMI Techniques | Ignition User Manual for some explanation of current thinking.

1 Like

Have to do some manipulation to get it to a web-safe color at the end, but the gradient built-in expression function will do a super basic linear interpolation across two colors for you.

1 Like

So serious :joy: Grave warning aside -- thank you for the expression! Pretty slick... This started as almost more of a "can it be done easily?" thought experiment when I realized this is a feature native to Microsoft Excel but has no obvious analog in Ignition. It's quickly progressed to the "should it be done?" stage, and of course the answer is no. But still, I might wake up one day with a wild hair up my ass, throw my High Performance HMI Handbook aside, and paste this into a little personal project or something... who really knows...