Home > database >  Break Colors Into Even Splits
Break Colors Into Even Splits

Time:08-19

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)

enter image description here

CodePudding user response:

Here is a base R way with functions colorRamp and rgb.

  1. create a deciles vector including the extremes 0 and 1 in the vector;
  2. find out where in the deciles vector are the heights;
  3. create a colors interpolation function with colorRamp;
  4. pass the shades, scaled to the interval [0, 1] to this function, the output is a RGB matrix;
  5. 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)

  • Related