Contrast between label and background: determine if color is light or dark
Here's a strategy to implement picking a text color of black vs white based on the intensity scale in the (second) link provided by @MrFlick.
The blog cited a W3C publication: a standard formula for calculating the perceived brightness of a color that used an algorithm for RGB encoded colors:
((Red value X 299) + (Green value X 587) + (Blue value X 114)) / 1000
The col2rgb
function delivers a 3-row matrix which I multiply by the factors offered in that webpage. I used an example of "red" as a background color and the chosen text would then be "white"
c( "black", "white")[ 1+(sum( col2rgb("red") *c(299, 587,114))/1000 < 123) ]
[1] "white"
Implemented as a function:
isDark <- function(colr) { (sum( col2rgb(colr) * c(299, 587,114))/1000 < 123) }
isDark("red")
[1] TRUE
How to decide font color in white or black depending on background color?
Building on my answer to a similar question.
You need to break the hex code into 3 pieces to get the individual red, green, and blue intensities. Each 2 digits of the code represent a value in hexadecimal (base-16) notation. I won't get into the details of the conversion here, they're easy to look up.
Once you have the intensities for the individual colors, you can determine the overall intensity of the color and choose the corresponding text.
if (red*0.299 + green*0.587 + blue*0.114) > 186 use #000000 else use #ffffff
The threshold of 186 is based on theory, but can be adjusted to taste. Based on the comments below a threshold of 150 may work better for you.
Edit: The above is simple and works reasonably well, and seems to have good acceptance here at StackOverflow. However, one of the comments below shows it can lead to non-compliance with W3C guidelines in some circumstances. Herewith I derive a modified form that always chooses the highest contrast based on the guidelines. If you don't need to conform to W3C rules then I'd stick with the simpler formula above. For an interesting look into the problems with this see Contrast Ratio Math and Related Visual Issues.
The formula given for contrast in the W3C Recommendations (WCAG 2.0) is (L1 + 0.05) / (L2 + 0.05)
, where L1
is the luminance of the lightest color and L2
is the luminance of the darkest on a scale of 0.0-1.0. The luminance of black is 0.0 and white is 1.0, so substituting those values lets you determine the one with the highest contrast. If the contrast for black is greater than the contrast for white, use black, otherwise use white. Given the luminance of the color you're testing as L
the test becomes:
if (L + 0.05) / (0.0 + 0.05) > (1.0 + 0.05) / (L + 0.05) use #000000 else use #ffffff
This simplifies down algebraically to:
if L > sqrt(1.05 * 0.05) - 0.05
Or approximately:
if L > 0.179 use #000000 else use #ffffff
The only thing left is to compute L
. That formula is also given in the guidelines and it looks like the conversion from sRGB to linear RGB followed by the ITU-R recommendation BT.709 for luminance.
for each c in r,g,b:
c = c / 255.0
if c <= 0.04045 then c = c/12.92 else c = ((c+0.055)/1.055) ^ 2.4
L = 0.2126 * r + 0.7152 * g + 0.0722 * b
The threshold of 0.179 should not be changed since it is tied to the W3C guidelines. If you find the results not to your liking, try the simpler formula above.
Determine if color is light or dark?
I haven't tested this, but it may work for you...
-(BOOL) isLightColor:(UIColor*)clr {
CGFloat white = 0;
[clr getWhite:&white alpha:nil];
return (white >= 0.5);
}
Colors: White if background is DARK and BLACK when is LIGHT
A simple solution is to add the color componets of the background color and compare them to a threshold.
You might want to give blue a lower weight. 0.3*R+0.6*G+0.1*B
is a common choice.
Determine font color based on background color
I encountered similar problem. I had to find a good method of selecting contrastive font color to display text labels on colorscales/heatmaps. It had to be universal method and generated color had to be "good looking", which means that simple generating complementary color was not good solution - sometimes it generated strange, very intensive colors that were hard to watch and read.
After long hours of testing and trying to solve this problem, I found out that the best solution is to select white font for "dark" colors, and black font for "bright" colors.
Here's an example of function I am using in C#:
Color ContrastColor(Color color)
{
int d = 0;
// Counting the perceptive luminance - human eye favors green color...
double luminance = (0.299 * color.R + 0.587 * color.G + 0.114 * color.B)/255;
if (luminance > 0.5)
d = 0; // bright colors - black font
else
d = 255; // dark colors - white font
return Color.FromArgb(d, d, d);
}
This was tested for many various colorscales (rainbow, grayscale, heat, ice, and many others) and is the only "universal" method I found out.
Edit
Changed the formula of counting a
to "perceptive luminance" - it really looks better! Already implemented it in my software, looks great.
Edit 2
@WebSeed provided a great working example of this algorithm: http://codepen.io/WebSeed/full/pvgqEq/
Text color based on contrast against background
Add these two code lines:
geom_text(aes(color = value > 0.1)) +
scale_color_manual(guide = FALSE, values = c("black", "white"))
Here text color depends on value (value > 0.1
) and colors are specified with scale_color_manual
.
For the output like this:
Finding out if a Hex color is dark or light
What if you convert your [Hex color to rgb][1] format then you make the summ of red green and blue
if it's over ((255*3)/2) it's a dark color, else it's light color
System.Drawing.Color col = System.Drawing.ColorTranslator.FromHtml("#FF2233");
if (col.R * 0.2126 + col.G * 0.7152 + col.B * 0.0722 < 255 / 2)
{
// dark color
}
else
{
// light color
}
Edit: Updated with Luminance, thanks to @Jon idea
[1]: How do I get the color from a hexadecimal color code using .NET?
Edit: fixed condition, thanks to @sam360
Map colors to labels in ggplot based on background color
Borrowing a code snippet from scales::show_col
to set the label colors according to the luminance of the fill colors to either "black" or "white" one option to achieve your desired result may look like so:
library(dplyr)
library(ggplot2)
library(carver)
fill_colors <- c("dark blue", "light blue", "green")
# Borrowed from scales::show_col
hcl <- farver::decode_colour(fill_colors, "rgb", "hcl")
label_col <- ifelse(hcl[, "l"] > 50, "black", "white")
df %>%
ggplot(data = ., aes(x = model, y = hwy, fill = cyl, label = hwy)) +
geom_bar(stat = "identity", position = "fill") +
geom_text(aes(color = cyl), position = position_stack(vjust = 0.5), show.legend = FALSE) +
scale_fill_manual(values = fill_colors,
name = "cyl",
breaks = c("4", "6", "8"),
labels = c("4", "6", "8")) +
scale_color_manual(values = label_col)
Check if UIColor is dark or bright?
W3C has the following:
http://www.w3.org/WAI/ER/WD-AERT/#color-contrast
If you're only doing black or white text, use the color brightness calculation above. If it is below 125, use white text. If it is 125 or above, use black text.
edit 1: bias towards black text. :)
edit 2: The formula to use is ((Red value * 299) + (Green value * 587) + (Blue value * 114)) / 1000.
If Form is dark, then Text on form should be Light
You could check, if the sum of the three rgb-values are above the half of the max-value
-> because 255,255,255 == white(light) and 0,0,0 == black(dark)
:
f.e.
R 255
G 140
B 170
=====
565
Max: 765 (Middle 382)
Sum: 565
Because the sum is 565 and above the middle (dark < 382 < light), the color is light. So you can change the textcolor to dark.
Related Topics
Accessing Parent Namespace Inside a Shiny Module
R Shiny Dt - Edit Values in Table with Reactive
Insert Function Variable into Graph Title
Error in Na.Fail.Default: Missing Values in Object - But No Missing Values
Update Plot Within Observer Loop in Shiny Application
How to Fill Histogram with Color Gradient
How to Underline Text in a Plot Title or Label? (Ggplot2)
Create a Reactive Function Outside the Shiny App
Making Multiple Style References in Google Maps API
Install.Packages R on Ubuntu 12.04 Downloads But Does Not Install Packages
Plot a Character Vector Against a Numeric Vector in R
Dplyr - Mutate Dynamically Named Variables Using Other Dynamically Named Variables
How to Deploy Shiny App That Uses Local Data
How to Automatically Load Data in an R Package
Write.Csv() a List of Unequally Sized Data.Frames
How to Rearrange an Order of Matches Between Two Data Frames