In this post, we will see how to convert colors from the RGB (red-green-blue) to the HEX (hexadecimal) system in R (and vice versa). For that, we will use base R and custom functions.
What is a RGB color?
A RGB color is composed of three to four values ranging from 0 to 255:
- one value for the red
- one value for the green
- one value for the blue
- one value for the transparency (facultative)
For example, a color with green and blue but no red is a kind of cyan:
red = 0
green = 196
blue = 255
Other examples:
- Black: red = 0, green = 0, blue = 0
- White: red = 255, green = 255, blue = 255
What is a hexadecimal number?
Contrary to everyday life where we use numbers in base-10 (10 numeric characters), the hexadecimal system uses numbers in base-16 (10 numeric characters and 6 alphabetic characters):
base-16 | base-10 |
0 | 0 |
1 | 1 |
2 | 2 |
3 | 3 |
4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
8 | 8 |
9 | 9 |
A | 10 |
B | 11 |
C | 12 |
D | 13 |
E | 14 |
F | 15 |
Number of possible two-character combinations:
- base 16: 16*16 = 256 possible combinations (from 0 to 255)
- base 10: 10*10 = 100 possible combinations (from 0 to 99)
What is a HEX color?
A hexadecimal color is composed of three to four pairs of characters ranging from 00 to FF:
- one pair for the red
- one pair for the green
- one pair for the blue
- one pair for the transparency (facultative)
For example, the “#00C4FF” color corresponds to the cyan rectangle above.
From RGB to HEX colors in R
1) Base R function
We can use the rgb function from base R but it requires numbers between 0 and 1. Therefore, we need to divide all values by 255, so that the maximum value (which is 255 in base 16) will be 1:
> rgb(red/255, green/255, blue/255)
[1] "#00C4FF"
2) Custom function
Why writing our own function? Because it is a good way to learn how it works! The function below extracts the value for each primary color (from 0 to 255), divide it by 16 to get the first number, take the remainder as second number and convert them from base 10 to base 16:
from_rgb_to_hex = function(red, green, blue){
conversion = data.frame(base_16 = c(seq(0, 9), "A", "B", "C", "D", "E", "F"),
base_10 = seq(0, 15))
hex = "#"
for (rgb in c(red, green, blue)){
hex_a = conversion[conversion[, "base_10"] == floor(rgb / 16), "base_16"]
hex_b = conversion[conversion[, "base_10"] == rgb %% 16, "base_16"]
hex = paste0(hex, hex_a, hex_b)
}
return(hex)
}
hex = from_rgb_to_hex(red, green, blue)
> from_rgb_to_hex(red, green, blue)
[1] "#00C4FF"
From HEX to RGB colors in R
1) Base R function
> col2rgb(hex)
[,1]
red 0
green 196
blue 255
2) Custom function
The function below extracts each pair of characters (corresponding to each primary color), converts them from base 16 to base 10 and then multiplies the first one with 16 before additioning it to the second one:
from_hex_to_rgb = function(hex){
conversion = data.frame(base_16 = c(seq(0, 9), "A", "B", "C", "D", "E", "F"),
base_10 = seq(0, 15))
hex = toupper(hex)
rgb = NULL
for (i in seq(2, 7, 2)){
rgb_a = substr(hex, start = i, stop = i)
rgb_a = conversion[conversion[, "base_16"] == rgb_a, "base_10"]
rgb_b = substr(hex, start = i+1, stop = i+1)
rgb_b = conversion[conversion[, "base_16"] == rgb_b, "base_10"]
rgb = c(rgb, rgb_a * 16 + rgb_b)
}
rgb = matrix(rgb)
mode(rgb) = "integer"
rownames(rgb) = c("red", "green", "blue")
return(rgb)
}
> from_hex_to_rgb(hex)
[,1]
red 0
green 196
blue 255
Thus, we have extracted the red, green and blues values from the hex color.
Conclusion
As the hexadecimal system to describe colors wasn’t straightforward for me, it was a good exercise to rewrite the rgb and col2rgb functions from base R. Is this article also useful to you?