Formatação condicional — porcentagem em conversão de cores
Pergunta
Qual é a maneira mais fácil de converter uma porcentagem em uma cor que varia de Verde (100%) a Vermelho (0%), com Amarelo para 50%?
Estou usando RGB simples de 32 bits - então cada componente é um número inteiro entre 0 e 255.Estou fazendo isso em C#, mas acho que para um problema como esse a linguagem não importa muito.
Com base nas respostas de Marius e Andy, estou usando a seguinte solução:
double red = (percent < 50) ? 255 : 256 - (percent - 50) * 5.12;
double green = (percent > 50) ? 255 : percent * 5.12;
var color = Color.FromArgb(255, (byte)red, (byte)green, 0);
Funciona perfeitamente - O único ajuste que tive que fazer na solução Marius foi usar 256, pois (255 - (por cento - 50) * 5,12 rende -1 quando 100%, resultando em Amarelo por algum motivo no Silverlight (-1, 255, 0 ) -> Amarelo ...
Solução
Fiz essa função em JavaScript.Ele retorna a cor é uma string css.Toma a porcentagem como variável, com intervalo de 0 a 100.O algoritmo pode ser feito em qualquer idioma:
function setColor(p){
var red = p<50 ? 255 : Math.round(256 - (p-50)*5.12);
var green = p>50 ? 255 : Math.round((p)*5.12);
return "rgb(" + red + "," + green + ",0)";
}
Outras dicas
O que você provavelmente deseja fazer é atribuir alguns pontos de 0% a 100% em um espaço de cores HSV ou HSL.A partir daí você pode interpolar cores (e o amarelo fica entre o vermelho e o verde :) e converta-os para RGB.Isso lhe dará um gradiente bonito entre os dois.
Supondo que você usará a cor como um indicador de status e do ponto de vista da interface do usuário, isso provavelmente não é uma boa ideia, já que somos muito ruins em ver pequenas mudanças na cor.Portanto, dividir o valor em, por exemplo, três a sete grupos proporcionaria diferenças mais perceptíveis quando as coisas mudam, ao custo de alguma precisão (que você provavelmente não seria capaz de avaliar de qualquer maneira).
Então, deixando de lado a matemática, no final eu recomendaria uma tabela de consulta com as seguintes cores, sendo v o valor de entrada:
#e7241d for v <= 12%
#ef832c for v > 12% and v <= 36%
#fffd46 for v > 36% and v <= 60%
#9cfa40 for v > 60% and v <= 84%
#60f83d for v > 84%
Estes foram convertidos muito ingenuamente de valores HSL (0,0, 1,0, 1,0), (30,0, 1,0, 1,0), (60,0, 1,0, 1,0), (90,0, 1,0, 1,0), (120,0, 1,0, 1,0) e você pode querer ajustar um pouco as cores para atender aos seus propósitos (alguns não gostam que o vermelho e o verde não sejam 'puros').
Por favor, veja:
- Usando cores HSL (matiz, saturação, luminosidade) para criar GUIs com melhor aparência para alguma discussão e
- Conversões de espaço de cores RGB e HSL para exemplo de código-fonte C#.
Em pseudocódigo.
De 0 a 50%, seu valor hexadecimal seria FFxx00 onde:
XX = ( Percentage / 50 ) * 255 converted into hex.
De 50 a 100, seu valor hexadecimal seria xxFF00, onde:
XX = ((100-Percentage) / 50) * 255 converted into hex.
Espero que ajude e seja compreensível.
Esta é uma solução agradável e limpa que melhora a resposta atualmente aceita de três maneiras:
- Remove o número mágico (5.12), tornando o código mais fácil de seguir.
- Não produzirá o erro de arredondamento que dá -1 quando a porcentagem é 100%.
- Permite personalizar os valores RGB mínimo e máximo usados, para que você possa produzir um intervalo mais claro ou mais escuro do que o simples rgb(255, 0, 0) - rgb(0, 255, 0).
O código mostrado é C# mas é trivial adaptar o algoritmo para qualquer outra linguagem.
private const int RGB_MAX = 255; // Reduce this for a darker range
private const int RGB_MIN = 0; // Increase this for a lighter range
private Color getColorFromPercentage(int percentage)
{
// Work out the percentage of red and green to use (i.e. a percentage
// of the range from RGB_MIN to RGB_MAX)
var redPercent = Math.Min(200 - (percentage * 2), 100) / 100f;
var greenPercent = Math.Min(percentage * 2, 100) / 100f;
// Now convert those percentages to actual RGB values in the range
// RGB_MIN - RGB_MAX
var red = RGB_MIN + ((RGB_MAX - RGB_MIN) * redPercent);
var green = RGB_MIN + ((RGB_MAX - RGB_MIN) * greenPercent);
return Color.FromArgb(red, green, RGB_MIN);
}
Notas
Aqui está uma tabela simples mostrando alguns valores percentuais e as proporções correspondentes de vermelho e verde que queremos produzir:
VALUE GREEN RED RESULTING COLOUR
100% 100% 0% green
75% 100% 50% yellowy green
50% 100% 100% yellow
25% 50% 100% orange
0% 0% 100% red
Espero que você possa ver claramente isso
- o valor verde é 2x o valor percentual (mas limitado a 100)
- o vermelho é o inverso:2x (100 - porcentagem) (mas limitado a 100)
Então, meu algoritmo calcula os valores de uma tabela parecida com esta ...
VALUE GREEN RED
100% 200% 0%
75% 150% 50%
50% 100% 100%
25% 50% 150%
0% 0% 200%
...e então usa Math.Min()
para limitá-los a 100%.
Eu escrevi esta função python com base no código javascript.leva uma porcentagem como decimal.também elevei o valor ao quadrado para manter as cores mais vermelhas por mais tempo na escala percentual.Também reduzi a gama de cores de 255 para 180 para dar um vermelho e verde mais escuro em cada extremidade.eles podem ser brincados para dar cores bonitas.Eu gostaria de adicionar um toque de laranja no meio, mas preciso continuar com o trabalho direito, cara.
def getBarColour(value):
red = int( (1 - (value*value) ) * 180 )
green = int( (value * value )* 180 )
red = "%02X" % red
green = "%02X" % green
return '#' + red + green +'00'
Como o amarelo é uma mistura de vermelho e verde, você provavelmente pode começar com #F00
e deslize verde para cima até atingir #FF0
, e deslize vermelho para baixo para #0F0
:
for (int i = 0; i < 100; i++) {
var red = i < 50
? 255
: 255 - (256.0 / 100 * ((i - 50) * 2));
var green = i < 50
? 256.0 / 100 * (i * 2)
: 255;
var col = Color.FromArgb((int) red, (int) green, 0);
}
Eu uso as seguintes rotinas Python para misturar cores:
def blendRGBHex(hex1, hex2, fraction):
return RGBDecToHex(blendRGB(RGBHexToDec(hex1),
RGBHexToDec(hex2), fraction))
def blendRGB(dec1, dec2, fraction):
return [int(v1 + (v2-v1)*fraction)
for (v1, v2) in zip(dec1, dec2)]
def RGBHexToDec(hex):
return [int(hex[n:n+2],16) for n in range(0,len(hex),2)]
def RGBDecToHex(dec):
return "".join(["%02x"%d for d in dec])
Por exemplo:
>>> blendRGBHex("FF8080", "80FF80", 0.5)
"BFBF80"
Outra rotina envolve isso para combinar perfeitamente entre valores numéricos para "formatação condicional":
def colourRange(minV, minC, avgV, avgC, maxV, maxC, v):
if v < minV: return minC
if v > maxV: return maxC
if v < avgV:
return blendRGBHex(minC, avgC, (v - minV)/(avgV-minV))
elif v > avgV:
return blendRGBHex(avgC, maxC, (v - avgV)/(maxV-avgV))
else:
return avgC
Então, no caso de Jonas:
>>> colourRange(0, "FF0000", 50, "FFFF00", 100, "00FF00", 25)
"FF7F00"
Minha solução para ActionScript 3:
var red:Number = (percentage <= 50) ? 255 : 256 - (percentage - 50) * 5.12;
var green:Number = (percentage >= 50) ? 255 : percentage * 5.12;
var redHex:Number = Math.round(red) * 0x10000;
var greenHex:Number = Math.round(green) * 0x100;
var colorToReturn:uint = redHex + greenHex;
Por ser RGB, as cores vão de valores inteiros de -1 (branco) a -16777216 para preto.com vermelho, verde e amarelo em algum lugar no meio disso.Na verdade, o amarelo é -256, enquanto o vermelho é -65536 e o verde é -16744448.Portanto, o amarelo na verdade não está entre o vermelho e o verde na notação RGB.Sei que em termos de comprimento de onda o verde está de um lado e o vermelho está do outro lado do espectro, mas nunca vi este tipo de notação usada em computadores, pois o espectro não representa todas as cores visíveis.