language agnostic - style - ¿Genera colores entre rojo y verde para un medidor de potencia?
rgb color mathematica (19)
Aquí está la solución de copiar y pegar para las escalas Swift y HSV:
El inicializador UIColor acepta matiz, saturación y brillo en [0, 1], por lo que para un valor dado de [0, 1] tenemos:
let hue: CGFloat = value / 3
let saturation: CGFloat = 1 // Or choose any
let brightness: CGFloat = 1 // Or choose any
let alpha: CGFloat = 1 // Or choose any
let color = UIColor(hue: hue, saturation: saturation, brightness: brightness, alpha: alpha)
Estoy escribiendo un juego de Java y quiero implementar un medidor de potencia para saber qué tan duro vas a disparar algo.
Necesito escribir una función que tome un int entre 0 - 100, y basado en cuán alto es ese número, devolverá un color entre Verde (0 en la escala de potencia) y Rojo (100 en la escala de potencia).
Similar a cómo funcionan los controles de volumen:
¿Qué operación debo hacer en los componentes Rojo, Verde y Azul de un color para generar los colores entre Verde y Rojo?
Por lo tanto, podría ejecutar, por ejemplo, getColor(80)
y devolverá un color anaranjado (sus valores en R, G, B) o getColor(10)
que devolverá un valor RGB más verde / amarillo.
Sé que necesito aumentar los componentes de los valores R, G, B para un nuevo color, pero no sé específicamente qué sube o baja a medida que los colores cambian de Verde a Rojo.
Progreso:
Terminé usando el espacio de color HSV / HSB porque me gustaba más el degradado (sin marrones oscuros en el medio).
La función que utilicé fue:
public Color getColor(double power)
{
double H = power * 0.4; // Hue (note 0.4 = Green, see huge chart below)
double S = 0.9; // Saturation
double B = 0.9; // Brightness
return Color.getHSBColor((float)H, (float)S, (float)B);
}
Donde "poder" es un número entre 0.0 y 1.0. 0.0 devolverá un rojo brillante, 1.0 volverá a un verde brillante.
Java Hue Chart:
Aquí está la versión Objective-C
de la solución de Simucal:
- (UIColor*) colorForCurrentLevel:(float)level
{
double hue = level * 0.4; // Hue (note 0.4 = Green)
double saturation = 0.9; // Saturation
double brightness = 0.9; // Brightness
return [UIColor colorWithHue:hue saturation:saturation brightness:brightness alpha:1.0];
}
Donde el nivel sería un valor entre 0.0
y 1.0
.
¡Espero que esto ayude a alguien!
Diría que quieres algo entre un segmento de línea en el espacio HSV (que tiene un amarillo ligeramente brillante en el centro) y un segmento de línea en el espacio RGB (que tiene un marrón feo en el centro). Yo usaría esto, donde power = 0
dará verde, power = 50
dará un amarillo ligeramente opaco, y power = 100
dará rojo.
blue = 0;
green = 255 * sqrt( cos ( power * PI / 200 ));
red = 255 * sqrt( sin ( power * PI / 200 ));
Ejemplo autónomo
<html>
<head>
<script>
//--------------------------------------------------------------------------
function gradient(left, mid, right)
{
var obj = {}
var lt50 = {"r":(mid.r-left.r)/50.0,
"g":(mid.g-left.g)/50.0,
"b":(mid.b-left.b)/50.0}
var gt50 = {"r":(right.r-mid.r)/50.0,
"g":(right.g-mid.g)/50.0,
"b":(right.b-mid.b)/50.0}
obj.getColor = function(percent) {
if (percent == 50.0) {
return mid;
}
if (percent < 50.0) {
return "rgb("+Math.floor(left.r+lt50.r*percent+0.5)+","+
Math.floor(left.g+lt50.g*percent+0.5)+","+
Math.floor(left.b+lt50.b*percent+0.5)+")";
}
var p2 = percent-50.0;
return "rgb("+Math.floor(mid.r+gt50.r*p2+0.5)+","+
Math.floor(mid.g+gt50.g*p2+0.5)+","+
Math.floor(mid.b+gt50.b*p2+0.5)+")";
}
return obj;
}
//--------------------------------------------------------------------------
var g_gradient = gradient( {"r":255, "g":20, "b":20}, // Left is red
{"r":255, "g":255, "b":20}, // Middle is yellow
{"r":20, "g":255, "b":20} ); // right is green
//--------------------------------------------------------------------------
function updateColor()
{
var percent = document.getElementById(''idtext'').value.length;
var oscore = document.getElementById(''idscore'');
if (percent > 100.0) {
percent = 100.0;
}
if (percent < 0.0) {
percent = 0.0;
}
var col = g_gradient.getColor(percent)
oscore.style[''background-color''] = col;
oscore.innerHTML = percent + ''%'';
}
</script>
</head>
<body onLoad="updateColor()">
<input size=''100'' placeholder=''type text here'' id=''idtext'' type="text" oninput="updateColor()" />
<br />
<br />
<div id=''idscore'' style=''text-align:center; width:200px; border-style:solid;
border-color:black; border-width:1px; height:20px;''> </div>
</body>
</html>
En Python 2.7:
import colorsys
def get_rgb_from_hue_spectrum(percent, start_hue, end_hue):
# spectrum is red (0.0), orange, yellow, green, blue, indigo, violet (0.9)
hue = percent * (end_hue - start_hue) + start_hue
lightness = 0.5
saturation = 1
r, g, b = colorsys.hls_to_rgb(hue, lightness, saturation)
return r * 255, g * 255, b * 255
# from green to red:
get_rgb_from_hue_spectrum(percent, 0.3, 0.0)
# or red to green:
get_rgb_from_hue_spectrum(percent, 0.0, 0.3)
El porcentaje es por supuesto value / max_value
. O si su escala no comienza en 0 entonces (value - min_value) / (max_value - min_value)
.
En la parte superior de mi cabeza, aquí está la transición de tono verde-rojo en el espacio HSV, traducido a RGB:
blue = 0.0
if 0<=power<0.5: #first, green stays at 100%, red raises to 100%
green = 1.0
red = 2 * power
if 0.5<=power<=1: #then red stays at 100%, green decays
red = 1.0
green = 1.0 - 2 * (power-0.5)
Los valores de rojo, verde y azul en el ejemplo anterior son porcentajes, es probable que desee multiplicarlos por 255 para obtener el rango 0-255 más utilizado.
Esto debería funcionar: simplemente escalar linealmente los valores rojo y verde. Suponiendo que su valor máximo de rojo / verde / azul es 255
, y n
está en el rango 0 .. 100
R = (255 * n) / 100
G = (255 * (100 - n)) / 100
B = 0
(Modificado para matemáticas enteras, punta del sombrero para Ferrucio)
Otra forma de hacerlo sería usar un modelo de color HSV , y cambiar el tono de 0 degrees
(rojo) a 120 degrees
(verde) con la saturación y el valor que le convenga. Esto debería dar un gradiente más agradable.
Aquí hay una demostración de cada técnica: el gradiente superior usa RGB, el inferior usa el HSV:
Esto variará de rojo a amarillo y luego a verde
el valor varía de 0 a 100
-(UIColor*) redToGreenColorWithPosition:(int) value {
double R, G;
if (value > 50) {
R = (255 * (100 - value)/ 50) ;
G = 255;
}else {
R = 255;
G = (255 * (value*2)) / 100;
}
return [UIColor colorWithRed:R/255.0f green:G/255.0f blue:0.0f alpha:1.0f];
}
He actualizado la respuesta aceptada dividiéndola en primera y segunda mitad del rango (0,100) y sustituyendo 100 por un nivel máximo, de modo que el rango pueda volverse dinámico. El resultado es exactamente como con el modelo HSV, pero aún usando RGB. La clave es tener el (255,255,0) en el medio para representar el color amarillo. He combinado esta idea en la respuesta aceptada y en otro código de VBA, por lo que lo logro en VBA y lo uso en Excel. Espero que la lógica ayude y se pueda usar en otros idiomas / aplicaciones.
Sub UpdateConditionalFormatting(rng As Range)
Dim cell As Range
Dim max As Integer
max = WorksheetFunction.max(rng)
For Each cell In rng.Cells
If cell.Value >= 0 And cell.Value < max / 2 Then
cell.Interior.Color = RGB(255 * cell.Value / (max / 2), 255, 0)
ElseIf cell.Value >= max / 2 And cell.Value <= max Then
cell.Interior.Color = RGB(255, 255 * ((max) - cell.Value) / (max / 2), 0)
End If
Next cell
End Sub
Saludos, Pavlin
Hice una pequeña función que le da el valor entero rgb para un valor porcentual:
private int getGreenToRedGradientByValue(int currentValue, int maxValue)
{
int r = ( (255 * currentValue) / maxValue );
int g = ( 255 * (maxValue-currentValue) ) / maxValue;
int b = 0;
return ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff);
}
Entonces, si su valor actual es 50 y su valor máximo es 100, esta función devolverá el color que necesita, de modo que si coloca esta función en bucle con un valor porcentual, su valor de color pasará de verde a rojo. Perdón por la mala explicación
La interpolación lineal entre verde y rojo casi debería funcionar, excepto que en el medio habrá un color marrón fangoso.
La solución más flexible y de mejor apariencia es tener un archivo de imagen en algún lugar que tenga la rampa de color exacta que desee. Y luego busca el valor de píxel allí. Esto tiene la flexibilidad de que puede ajustar el degradado para que sea el correcto .
Si aún desea hacerlo desde el código, probablemente sea mejor interpolar entre los colores verde y amarillo en el lado izquierdo, y entre el amarillo y el rojo en el lado derecho. En el espacio RGB, el verde es (R = 0, G = 255, B = 0), el amarillo es (R = 255, G = 255, B = 0), el rojo es (R = 255, G = 0, B = 0 ) - esto supone que cada componente de color va de 0 a 255.
La respuesta aceptada ni siquiera realmente respondió la pregunta ...
C ++
Aquí hay un segmento simple de código C ++ de mi motor que interpola linealmente y eficientemente entre tres colores arbitrarios:
const MATH::FLOAT4 color1(0.0f, 1.0f, 0.0f, 1.0f); // Green
const MATH::FLOAT4 color2(1.0f, 1.0f, 0.0f, 1.0f); // Yellow
const MATH::FLOAT4 color3(1.0f, 0.0f, 0.0f, 1.0f); // Red
MATH::FLOAT4 get_interpolated_color(float interpolation_factor)
{
const float factor_color1 = std::max(interpolation_factor - 0.5f, 0.0f);
const float factor_color2 = 0.5f - fabs(0.5f - interpolation_factor);
const float factor_color3 = std::max(0.5f - interpolation_factor, 0.0f);
MATH::FLOAT4 color;
color.x = (color1.x * factor_color1 +
color2.x * factor_color2 +
color3.x * factor_color3) * 2.0f;
color.y = (color1.y * factor_color1 +
color2.y * factor_color2 +
color3.y * factor_color3) * 2.0f;
color.z = (color1.z * factor_color1 +
color2.z * factor_color2 +
color3.z * factor_color3) * 2.0f;
color.w = 1.0f;
return(color);
}
Se supone que el interpolation_factor
está en el rango de 0.0 ... 1.0
.
Se supone que los colores están en el rango de 0.0 ... 1.0
(por ejemplo, para OpenGL).
DO#
Aquí está la misma función escrita en C #:
private readonly Color mColor1 = Color.FromArgb(255, 0, 255, 0);
private readonly Color mColor2 = Color.FromArgb(255, 255, 255, 0);
private readonly Color mColor3 = Color.FromArgb(255, 255, 0, 0);
private Color GetInterpolatedColor(double interpolationFactor)
{
double interpolationFactor1 = Math.Max(interpolationFactor - 0.5, 0.0);
double interpolationFactor2 = 0.5 - Math.Abs(0.5 - interpolationFactor);
double interpolationFactor3 = Math.Max(0.5 - interpolationFactor, 0.0);
return (Color.FromArgb(255,
(byte)((mColor1.R * interpolationFactor1 +
mColor2.R * interpolationFactor2 +
mColor3.R * interpolationFactor3) * 2.0),
(byte)((mColor1.G * interpolationFactor1 +
mColor2.G * interpolationFactor2 +
mColor3.G * interpolationFactor3) * 2.0),
(byte)((mColor1.B * interpolationFactor1 +
mColor2.B * interpolationFactor2 +
mColor3.B * interpolationFactor3) * 2.0)));
}
Se supone que el interpolationFactor
está en el rango de 0.0 ... 1.0
.
Se supone que los colores están en el rango de 0 ... 255
.
Necesita interpolar linealmente (LERP) los componentes de color. Así es como se hace en general, dado un valor inicial v0 , un valor final v1 y la proporción requerida (un valor flotante normalizado entre 0.0 y 1.0):
v = v0 + ratio * (v1 - v0)
Esto da v0 cuando la relación es 0.0, v1 cuando la razón es 1.0 y todo lo que está entre los otros casos.
Puede hacerlo en los componentes RGB o utilizando algún otro esquema de color, como HSV o HLS. Los dos últimos serán más agradables a la vista, ya que trabajan en matices y brillos que se ajustan mejor a nuestra percepción del color.
Respuesta breve de Copy''n''Paste ...
En Java Std:
int getTrafficlightColor(double value){
return java.awt.Color.HSBtoRGB((float)value/3f, 1f, 1f);
}
En Android:
int getTrafficlightColor(double value){
return android.graphics.Color.HSVToColor(new float[]{(float)value*120f,1f,1f});
}
nota: valor es un número entre 0 y 1 que indica la condición de rojo a verde.
Si desea una representación verde-amarillo-rojo como sugiere la respuesta aceptada, eche un vistazo a esto.
http://jsfiddle.net/0awncw5u/2/
function percentToRGB(percent) {
if (percent === 100) {
percent = 99
}
var r, g, b;
if (percent < 50) {
// green to yellow
r = Math.floor(255 * (percent / 50));
g = 255;
} else {
// yellow to red
r = 255;
g = Math.floor(255 * ((50 - percent % 50) / 50));
}
b = 0;
return "rgb(" + r + "," + g + "," + b + ")";
}
function render(i) {
var item = "<li style=''background-color:" + percentToRGB(i) + "''>" + i + "</li>";
$("ul").append(item);
}
function repeat(fn, times) {
for (var i = 0; i < times; i++) fn(i);
}
repeat(render, 100);
li {
font-size:8px;
height:10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<ul></ul>
Si necesita este tipo de degradado (realmente revertido) en CSS (versión mínima 2.1) también puede usar HSL.
Supongamos que está en una plantilla de AngularJs y el valor es un número del 0 al 1 y desea aplicar un estilo a un elemento (color de fondo o de texto) ...
hsl({{ value * 120}}, 50%, 35%)
Primer valor: grados (0 rojo, 120 verde) Segundo valor: saturación (50% es neutral) Tercer valor: luminosidad (50% neutro)
Un buen artículo here
Teoría en Wikipedia here
VB
Public Function GetPercentageColor( _
ByVal iPercent As Long, Optional _
ByVal bOpposit As Boolean) As Long
'' 0->100% - Green->Yellow->Red
'' bOpposit - Red->Yellow->Green
If bOpposit Then iPercent = (100 - iPercent)
Select Case iPercent
Case Is < 1: GetPercentageColor = 65280 '' RGB(0, 255, 0)
Case Is > 99: GetPercentageColor = 255 '' RGB(255, 0, 0)
Case Is < 50: GetPercentageColor = RGB(255 * iPercent / 50, 255, 0)
Case Else: GetPercentageColor = RGB(255, (255 * (100 - iPercent)) / 50, 0)
End Select
End Function
JavaScript
Estoy usando Google Visualization con un gráfico de barras y quería que las barras fueran de verde a rojo según un porcentaje. Esta resultó ser la solución más limpia que encontré y funciona perfectamente.
function getGreenToRed(percent){
r = percent<50 ? 255 : Math.floor(255-(percent*2-100)*255/100);
g = percent>50 ? 255 : Math.floor((percent*2)*255/100);
return ''rgb(''+r+'',''+g+'',0)'';
}
Solo asegúrate de que tu porcentaje sea 50 para 50% y no 0.50.
import java.awt.Color;
public class ColorUtils {
public static Color interpolate(Color start, Color end, float p) {
float[] startHSB = Color.RGBtoHSB(start.getRed(), start.getGreen(), start.getBlue(), null);
float[] endHSB = Color.RGBtoHSB(end.getRed(), end.getGreen(), end.getBlue(), null);
float brightness = (startHSB[2] + endHSB[2]) / 2;
float saturation = (startHSB[1] + endHSB[1]) / 2;
float hueMax = 0;
float hueMin = 0;
if (startHSB[0] > endHSB[0]) {
hueMax = startHSB[0];
hueMin = endHSB[0];
} else {
hueMin = startHSB[0];
hueMax = endHSB[0];
}
float hue = ((hueMax - hueMin) * p) + hueMin;
return Color.getHSBColor(hue, saturation, brightness);
}
}