Suppose I have this data in R:
heights = rnorm(1000, 150, 10)
deciles = quantile(heights, probs = seq(.1, .9, by = .1))
10% 20% 30% 40% 50% 60% 70% 80% 90%
137.8206 142.2595 145.4719 147.6242 149.8734 152.1049 154.9373 158.6607 163.1900
I want to assign a color to each of these heights. I want to make it in such a way, such that all observations between 0 - 137.8206 are light color, all observations between 137.8206 - 142.2595 are a slightly darker color .... and all observations between 158.6607 - 163.1900 are the darkest color. For example, 0 - 137.8206 are a very light shade of red and 158.6607 - 163.1900 are a very dark shade of red.
I was thinking of manually trying to find the min and max range of a red color, and then trying to manually create these breaks - but I think there is a chance I might make a mistake doing this and was looking for a more automatic way of doing this. In the end, I would like a data frame that looks something like this:
height color
1 148.5791 #FF0000
2 136.1866 #FF4500
3 155.2477 #FF0000
- Is there an easier way to do this?
Thank you!
CodePudding user response:
I would recommend using the cut
function with the breaks
arguments defining your levels for the color changes. The result of this can then be used as an index to select your desired colors.
set.seed(1)
df <- data.frame(heights = rnorm(1000, 150, 10))
(deciles = quantile(df$heights, probs = seq(.1, .9, by = .1)))
breaks <- c(-Inf, deciles["10%"], deciles["80%"], Inf)
COLS <- c("pink", "red", "red4")
df$color <- COLS[cut(df$heights, breaks = breaks)]
head(df)
plot(df$heights, col = df$color, pch = ".", cex = 5)
CodePudding user response:
Here is a base R way with functions colorRamp
and rgb
.
- create a deciles vector including the extremes 0 and 1 in the vector;
- find out where in the deciles vector are the heights;
- create a colors interpolation function with
colorRamp
; - pass the shades, scaled to the interval [0, 1] to this function, the output is a RGB matrix;
- transform the RGB levels into hex codes with function
rgb
.
set.seed(2022)
heights <- rnorm(1000, 150, 10)
deciles <- quantile(heights, probs = (0:10)/10)
range(heights)
#> [1] 115.2477 187.6519
shades <- findInterval(heights, deciles)
colors_fun <- colorRamp(c("white", "red", "darkred"))
rgb_matrix <- colors_fun(shades/max(shades))
head(rgb_matrix)
#> [,1] [,2] [,3]
#> [1,] 181.1818 0.00000 0.00000
#> [2,] 255.0000 162.27273 162.27273
#> [3,] 255.0000 162.27273 162.27273
#> [4,] 255.0000 208.63636 208.63636
#> [5,] 255.0000 69.54545 69.54545
#> [6,] 255.0000 208.63636 208.63636
clrs <- rgb(colors_fun(shades/max(shades)), max = 255)
plot(1:1000, heights, col = clrs, pch = 16, cex = 2)
Created on 2022-08-18 by the reprex package (v2.0.1)
So to create the data.frame, assign the hex codes returned by rgb
to their column.
df_colors <- data.frame(height = heights, color = clrs)
head(df_colors)
#> height color
#> 1 159.5668 #B50000
#> 2 134.2518 #FFD0D0
#> 3 151.9641 #F40000
#> 4 153.9582 #DF0000
#> 5 159.8854 #B50000
#> 6 154.7081 #DF0000
Created on 2022-08-18 by the reprex package (v2.0.1)
Edit
Though not asked, to have an alpha channel, use colorRamp
argument alpha
.
colors_alpha_fun <- colorRamp(c("white", "red", "darkred"), alpha = TRUE)
rgb_alpha_matrix <- colors_alpha_fun(shades/max(shades))
# transparency set to half the maximum
rgb_alpha_matrix[, 4] <- floor(255*0.5)
head(rgb_alpha_matrix)
#> [,1] [,2] [,3] [,4]
#> [1,] 181.1818 0.00000 0.00000 127
#> [2,] 255.0000 162.27273 162.27273 127
#> [3,] 255.0000 162.27273 162.27273 127
#> [4,] 255.0000 208.63636 208.63636 127
#> [5,] 255.0000 69.54545 69.54545 127
#> [6,] 255.0000 208.63636 208.63636 127
clrs_alpha <- rgb(
red = rgb_alpha_matrix[,1],
green = rgb_alpha_matrix[,2],
blue = rgb_alpha_matrix[,3],
alpha = rgb_alpha_matrix[,4],
max = 255
)
plot(1:1000, heights, col = clrs_alpha, pch = 16, cex = 2)
df_colors_alpha <- data.frame(height = heights, color = clrs_alpha)
head(df_colors_alpha)
#> height color
#> 1 159.0014 #B500007F
#> 2 138.2665 #FFA2A27F
#> 3 141.0251 #FFA2A27F
#> 4 135.5550 #FFD0D07F
#> 5 146.6899 #FF45457F
#> 6 120.9937 #FFD0D07F
Created on 2022-08-18 by the reprex package (v2.0.1)